在亿级流量系统的架构系列中,我们已深入剖析了降级、限流、隔离、负载均衡等核心技术,也探讨了缓存、队列、重试等性能优化关键点。然而,当流量洪峰真正来袭时,仅靠业务层优化往往不够——我们更需要一个高性能、可编程的流量控制枢纽,在请求抵达业务逻辑前完成高效调度与过滤。
这就是今天要讲的OpenResty。它基于Nginx与Lua,将网关层的性能潜力释放到极致:既能实现毫秒级缓存、动态负载均衡与精准限流,又能通过Lua脚本灵活编写业务逻辑,真正让网关成为“流量治理的第一战场”。本文将带你深入OpenResty的核心设计、生态体系与架构模式,看它如何以单机闭环之巧力,扛起分布式场景的亿级流量冲击。
Nginx优点
Nginx设计为一个主进程多个工作进程的工作模式,每个进程是单线程来处理多个 连接,而且每个工作进程采用了非阻塞I/O来处理多个连接,从而减少了线程上下文切 换,实现了公认的高性能、高并发。因此,在生成环境中会通过把CPU绑定给Nginx 工作进程,从而提升其性能。另外,因为单线程工作模式的特点,内存占用就非常少了。
Nginx更改配置后重启速度非常快,可以达到毫秒级,而且支持不停止Nginx进行 升级Nginx版本、动态重载Nginx配置。
Nginx模块也非常多,功能也很强劲,不仅可以作为HTTP负载均衡,Nginx发布 1.9.0版本还支持TCP负载均衡,还可以很容易地实现内容缓存、Web服务器、反向代理、访问控制等功能。
Lua的优点
Lua是一种轻量级、可嵌入式的脚本语言,可以非常容易地嵌入到其他语言中使用。
另外,Lua提供了协程并发,即以同步调用的方式进行异步执行,从而实现并发,比起 回调机制的并发来说代码更容易编写和理解,排查问题也会更容易。
Lua还提供了闭包机制,函数可以作为First Class Value进行参数传递,另外,其实现了标记清除垃圾 收集。
因为Lua的小巧轻量级,可以在Nginx中嵌入Lua VM,请求的时候创建一个VM, 请求结束的时候回收VM。
什么是ngx_lua
ngx_lua是Nginx的一个模块,将Lua嵌入到Nginx中,从而可以使 用Lua来编写脚本,部署到Nginx中运行,即Nginx变成了一个Web容器。这样开发 人员就可以使用Lua语言开发高性能Web 应用了。
ngx_lua提供了与Nginx交互的很多API,对于开发人员来说只需要学习这些API 就可以进行功能开发,而对于开发Web应用来说,如果接触过Servlet的话,你会发现 其开发和Servlet类似,无外乎就是知道接收请求、参数解析、功能处理、返回响应这 几步的API是什么样子的。
OpenResty生态
OpenResty提供了一些常用的ngx_lua开发模块,如lua-resty-memcached、lua-restymysql、lua-resty-redis、lua-resty-dns、lua-resty-limit-traffic、lua-resty-template。 这些模块涉及如MySQL数据库、Redis、限流、模块渲染等常用功能组件。另外, 也有很多第三方的ngx_lua组件供我们使用,对于大部分应用场景来说,现在生态环境 中的组件已经足够多了。如果不满足需求,那么也可以自己去写来完成需求。
应用场景
目前CDN厂商使用OpenResty较多,而复杂的Web 应用。目前见到的一些应用场景如下。
1、Web应用:商品的列表页/商品详情页。
2、接入网关:实现如数据校验前置、缓存前置、数据过滤、API请求聚合、A/B 测试、灰度发布、降级、监控等功能。
3、Web防火墙:可以进行IP/URL/UserAgent/Referer黑名单、限流等功 能。
4、缓存服务器:可以对响应内容进行缓存,减少到达后端的请求,从而提升性能。
5、其他:如静态资源服务器、消息推送服务、缩略图裁剪等。
负载均衡:流量分发与水平扩容
如下图所示,我们首先通过LVS+HAProxy将流量转发给核心Nginx1和核心Nginx 2,即实现了流量的负载均衡,此处可以使用如轮询、一致性哈希等调度算法来实现负载的转发。然后核心Nginx会根据请求特征如"Host.iem.jd.com",转发给相应的业务 Nginx节点,如单品页Nginx1。此处为什么分两层呢?
业务Nginx一般会把请求直接转发给后端的业务应用,如Tomcat、PHP,即将请求 内部转发到相应的业务应用。当有的Tomcat出现问题时,可以在这一层摘掉。或者有 的业务路径变了在这一层进行重写。或者有的后端Tomcat 压力太大也可以在这一层降 级,减少对后端冲击。或者业务需要灰度发布时,也可以在这一层Nginx上控制。
单机闭环
所谓单机闭环即所有想要的数据都能从本服务器中直接获取,在大多数时候无须通过网络去其他服务器获取。如下图所示,主要有三种应用模式。
左边第一幅图的应用场景是Nginx应用谁也不依赖,比如,我们的Cookie白名单 应用,其目的是不在白名单中的Cookie将被清理,防止大家随便将Cookie写根下,大家访问
时,会看到一个
https://api.m.jd.com/?functionId=pchome_cookie_check&appid=www-jd-com&cthr=1&source=pc-home
请求用来清理Cookie。
对于这种应用非常简单,不需要依赖数据源,直接单应用闭环即可。中间那幅的场景,是读取本机文件系统,如静态资源合并。
前有成熟的Nginx模块(如nginx-http-concat)进行静态资源合并。因为我们使用了OpenResty,所以我们完全可以使用Lua编写程序实现该功能,比如,已经有人写 了nginx-lua-static-merger来实现这个功能。
高可用闭环方式
分布式闭环
单机闭环会遇到如下两个主要问题:数据不一致问题(比如,没有采用主从架构导致不同服务器数据不一致);存储瓶颈问题(磁盘或者内存遇到了天花板)。
解决数据不一致的比较好的办法是采用主从或者分布式集中存储。而遇到存储瓶颈 就需要进行按照业务键进行分片,将数据分散到多台服务器。如采用如下页图所示的架构。
第一步先读取Redis集群。如果不命中,则回源到Tomcat集群(其会调用数据库、服务总线获取相关数据) 来获取相关数据。redis集群会进行多机房主从同步,各自机房读取自己机房的从redis集群,如 下图所示。
到此我们对于Nginx开发已经有了一个整体认识,将Nginx黏合Lua来开发应用可 以说是一把锋利的瑞士军刀,可以帮我们很容易地解决很多问题,可以开发Web 应用、 接入网关、API网关、消息推送、日志采集等应用,不过,个人认为适合开发业务逻辑单一、核心代码行数较少的应用,不适合业务逻辑复杂、功能繁多的业务型或者企业级应用。
最后我们总结一下基于Nginx+Lua的常用架构模式中的一些常见实践和场景,包括:动态负载均衡、防火墙(DDoS、IP/URL/UserAgent/Referer黑名单、防盗链等)、 限流、降级、A/B测试和灰度发布、多级缓存模式、服务器端请求聚合、服务质量监控。
在开发Nginx应用时,使用UTF-8编码可以减少很多麻烦。
GBK转码解码时,应使用GB18030,否则一些特殊字符会出现乱码。
根据业务设置合理的超时时间。
运行CDN的业务,当发生错误时,不要给返回的500/503/302/301等非正常响应。
阅读原文:原文链接
该文章在 2025/9/4 13:23:42 编辑过