Nginx作为一个高性能的Web服务器和反向代理服务器,已经稳定运行了多年。然而,考虑到后续分馆流量的接入,会对我们的系统造成难以预估的影响,因此在网关层对流量进行监控并管理就显得格外重要。本次调研目标为OpenResty,研究评估其是否值得将其引入替换原生Nginx
OpenResty是一个基于Nginx的Web服务器扩展,它结合了Nginx的高性能和Lua编程的灵活性,为开发人员提供了一个强大的工具来构建高性能、可扩展和定制化的Web应用程序。本文将介绍OpenResty的特点、用途、架构、Lua编程、性能优势以及如何入门使用OpenResty。
我收集了目前市面上常见的几种流量网关,分别是OpenResty、Tengine、Kong和APISIX,以下是这四个不同的技术/产品的比较:
比较总结:
OpenResy分为两个版本
其中开源版本需要自行组合各种库或用自己编写Lua来实现
而OpenResty Edge是完整的解决方案,开箱即用并且提供了管理界面,更易用,也有私有库私有功能
OpenResty的架构基于Nginx,但添加了一些关键组件,如LuaJIT和ngx_lua模块。下面是OpenResty的主要组件:
Nginx的底层模块一般都是用 C 语言写 的,如果我们想在 Nginx 的基础之上写业务逻辑会很不方便,所以这个时候我们还得借助 OpenResty,它是 Nginx 的一个社区分支。OpenResty 是中国人章亦春 发起,最早是雅虎中国的一个公司项目,基于 Perl 和 Haskell 实现,2007年开始开源,后来章亦春大佬加入淘宝后进行了彻底的设计和重写。
按照官网的说法,OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
Nginx 服务器启动后,产生一个 Master 进程(Master Process),Master 进程执行一系列工作后产生一个或者多个 Worker 进程(Worker Processes)。其中,Master 进程用于接收来自外界的信号,并向各 Worker 进程发送信号,同时监控 Worker 进程的工作状态。当 Worker 进程退出后(异常情况下),Master 进程也会自动重新启动新的 Worker 进程。Worker 进程则是外部请求真正的处理者。
多个 Worker 进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个 Worker 进程中处理,一个 Worker 进程不可能处理其它进程的请求。Worker 进程的个数是可以设置的,一般我们会设置与机器 CPU 核数一致。同时,Nginx 为了更好的利用多核特性,具有 CPU 绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来 cache 的失效(CPU affinity)。所有的进程的都是单线程(即只有一个主线程)的,进程之间通信主要是通过共享内存机制实现的。
OpenResty 本质上是将 LuaJIT 的虚拟机嵌入到 Nginx 的管理进程和工作进程中,同一个进程内的所有协程都会共享这个虚拟机,并在虚拟机中执行 Lua 代码。在性能上,OpenResty 接近或超过 Nginx 的 C 模块,而且开发效率更高。
-- 文件名:ip_monitor.lua
local ip = ngx.var.remote_addr -- 获取客户端IP地址
-- 打开文件句柄,指定日志文件的路径
local log_file = "/usr/local/openresty/nginx/lua/ip_monitor.log"
local file, err = io.open(log_file, "a")
if not file then
ngx.log(ngx.ERR, "failed to open log file: ", err)
return ngx.exit(500)
end
-- 写入日志
local log_message = "IP: " .. ip .. " 访问了网站\n"
local _, err = file:write(log_message)
if err then
ngx.log(ngx.ERR, "failed to write log: ", err)
end
-- 关闭文件句柄
file:close()
location / {
content_by_lua_file /usr/local/openresty/nginx/lua/ip_monitor.log;
# 其他配置项
}
http {
...
lua_shared_dict my_limit 10m; # 定义一个名为my_limit的共享内存字典,大小为10MB
...
}
-- 文件名:rate_limit.lua
local limit_req = require("resty.limit.req")
-- 使用正确的共享内存字典名称
local lim, err = limit_req.new("my_limit", 1, 1) -- 使用my_limit字典
if not lim then
ngx.log(ngx.ERR, "failed to create rate limiter: ", err)
return ngx.exit(500)
end
-- 检查客户端IP是否超出限制
local key = ngx.var.remote_addr
local delay, err = lim:incoming(key, true)
if not delay then
if err == "rejected" then
return ngx.exit(503) -- 返回503状态码表示请求被限制
end
ngx.log(ngx.ERR, "failed to limit req: ", err)
return ngx.exit(500)
end
location / {
content_by_lua_file /path/to/rate_limit.lua;
# 其他配置项
}
sudo nginx -s reload
由此可见使用OpenResty进行简单开发即可以轻松完成流量监控以及限流操作,它继承了Nginx的性能优势,通过Lua编程提供了灵活性和可定制性。对于处理高流量和复杂逻辑的应用程序,OpenResty是一个强大的选择。通过使用OpenResty,可以大幅提高Web应用程序的性能和功能。