OpenResty 是一个基于 Nginx 与 LuaJIT 的高性能 Web 平台,它将 Nginx 从静态配置服务器转变为动态应用平台。本文详细介绍 OpenResty 的核心特性、安装部署、Lua 模块使用以及实战应用场景,帮助开发者掌握如何通过 Lua 脚本扩展 Nginx 功能,构建高性能的 Web 应用和 API 网关。
目录
为什么需要 OpenResty?
OpenResty 与 Nginx 的核心区别
OpenResty 安装与配置
第一个 OpenResty Lua 程序
Lua 模块指令详解
实战应用场景
性能优化建议
总结
1. 为什么需要 OpenResty?
传统的 Nginx 以其高性能、低内存消耗和高并发处理能力而闻名,但它主要依赖静态配置文件,缺乏动态编程能力。当需要实现复杂的业务逻辑时,通常需要将请求转发到后端应用服务器,这会增加网络延迟和系统复杂度。
OpenResty 通过集成 LuaJIT(Lua 即时编译器)和一系列精选的 Nginx 模块,解决了这个问题。它允许开发者在 Nginx 的请求处理生命周期中直接嵌入 Lua 脚本,实现动态路由、实时数据处理、复杂鉴权等高级功能,而无需额外的后端服务。
2. OpenResty 与 Nginx 的核心区别
特性维度
Nginx
OpenResty
核心定位
高性能 HTTP/反向代理服务器
基于 Nginx 的 Web 应用平台
扩展方式
C 模块开发,需重新编译
Lua 脚本,运行时动态加载
动态逻辑
需反向代理到后端处理
直接执行 Lua 脚本
开发效率
修改配置需重启服务
支持代码热加载(开发模式)
数据库访问
不支持原生非阻塞访问
内置非阻塞 MySQL/Redis 等客户端
典型延迟
0.2ms(基础路由)
0.5ms(含 Lua 逻辑)
OpenResty 不仅仅是 Nginx 的增强版,它是一个完整的 Web 应用开发平台,特别适合需要高性能和动态处理能力的场景。
3. OpenResty 安装与配置
3.1 系统要求
支持系统:Ubuntu/Debian、CentOS/RHEL、macOS、Windows(WSL)
依赖工具:gcc、make、pcre-devel、openssl-devel、zlib-devel
3.2 安装方式
方式一:使用官方预编译包(推荐)
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y wget gnupg ca-certificates
wget -O – https://openresty.org/package/pubkey.gpg | sudo apt-key add –
echo “deb http://openresty.org/package/ubuntu $(lsb_release -sc) main” | sudo tee /etc/apt/sources.list.d/openresty.list
sudo apt-get update
sudo apt-get install -y openresty
# CentOS/RHEL/Rocky Linux
sudo yum install -y yum-utils
sudo yum-config-manager –add-repo https://openresty.org/package/centos/openresty.repo
sudo yum install -y openresty
方式二:源码编译安装(自定义需求)
# 下载源码
wget https://openresty.org/download/openresty-1.27.1.2.tar.gz
tar -zxvf openresty-1.27.1.2.tar.gz
cd openresty-1.27.1.2
# 配置编译选项
./configure –prefix=/usr/local/openresty \
–with-luajit \
–with-http_ssl_module \
–with-http_realip_module \
–with-http_stub_status_module
# 编译安装
make -j$(nproc)
sudo make install
方式三:Docker 安装
docker pull openresty/openresty:latest
docker run -d –name openresty -p 80:80 -v /path/to/conf:/usr/local/openresty/nginx/conf openresty/openresty
3.3 验证安装
# 检查版本
openresty -v
# 或
/usr/local/openresty/bin/openresty -v
# 启动服务
sudo systemctl start openresty
sudo systemctl enable openresty
4. 第一个 OpenResty Lua 程序
4.1 创建项目目录结构
mkdir -p ~/openresty-demo/{logs,conf,lua}
cd ~/openresty-demo
4.2 编写 Nginx 配置文件
创建 conf/nginx.conf文件:
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
# 设置 Lua 模块搜索路径
lua_package_path “$prefix/lua/?.lua;;”;
server {
listen 8080;
server_name localhost;
location / {
default_type text/html;
content_by_lua_block {
ngx.say(“<h1>Hello, OpenResty!</h1>”)
ngx.say(“<p>当前时间: ” .. os.date(“%Y-%m-%d %H:%M:%S”) .. “</p>”)
ngx.say(“<p>请求URI: ” .. ngx.var.request_uri .. “</p>”)
}
}
location /api/hello {
content_by_lua_file lua/hello.lua;
}
location /api/user {
access_by_lua_block {
— 简单的鉴权逻辑
local token = ngx.req.get_headers()[“Authorization”]
if not token or token ~= “Bearer secret-token” then
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
}
content_by_lua_block {
local args = ngx.req.get_uri_args()
local name = args.name or “Guest”
ngx.say(‘{“status”: “success”, “message”: “Hello, ‘ .. name .. ‘”}’)
ngx.header[“Content-Type”] = “application/json”
}
}
}
}
4.3 创建 Lua 模块
创建 lua/hello.lua文件:
local _M = {}
function _M.greet(name)
return “Hello, ” .. (name or “World”) .. ” from Lua module!”
end
function _M.handle_request()
local args = ngx.req.get_uri_args()
local name = args.name or “Anonymous”
ngx.header[“Content-Type”] = “application/json”
ngx.say(‘{“message”: “‘ .. _M.greet(name) .. ‘”, “timestamp”: “‘ .. os.date(“%Y-%m-%dT%H:%M:%S”) .. ‘”}’)
end
return _M
4.4 启动并测试
# 启动 OpenResty
/usr/local/openresty/bin/openresty -p ~/openresty-demo/ -c conf/nginx.conf
# 测试访问
curl http://localhost:8080/
curl “http://localhost:8080/api/hello?name=Developer”
curl -H “Authorization: Bearer secret-token” “http://localhost:8080/api/user?name=John”
5. Lua 模块指令详解
OpenResty 在 Nginx 的不同处理阶段提供了对应的 Lua 指令,允许开发者在请求生命周期的各个阶段插入 Lua 逻辑。
5.1 核心 Lua 指令
指令
执行阶段
描述
示例
init_by_lua
初始化阶段
Nginx Master 进程启动时执行
init_by_lua ‘cjson = require “cjson”‘
init_worker_by_lua
Worker 初始化
每个 Worker 进程启动时执行
定时任务初始化
set_by_lua
重写阶段
设置 Nginx 变量
set_by_lua $sum ‘return 32 + 56’
rewrite_by_lua
重写阶段
URL 重写逻辑
动态路由、A/B 测试
access_by_lua
访问控制阶段
权限验证、限流
JWT 验证、IP 黑白名单
content_by_lua
内容生成阶段
生成响应内容
动态 API 响应
header_filter_by_lua
响应头过滤
修改响应头
添加自定义 Header
body_filter_by_lua
响应体过滤
修改响应体
内容压缩、过滤
log_by_lua
日志记录阶段
自定义日志
请求统计、审计日志
5.2 配置示例:完整的请求处理流程
http {
lua_shared_dict my_cache 10m; # 共享内存缓存
init_by_lua_block {
— 全局初始化
require “resty.core”
package.path = “/usr/local/openresty/lualib/?.lua;” .. package.path
}
server {
listen 80;
location /api {
# 1. 重写阶段:参数处理
rewrite_by_lua_block {
local args = ngx.req.get_uri_args()
if args.version == “v2” then
ngx.req.set_uri(“/api/v2” .. ngx.var.request_uri)
end
}
# 2. 访问控制:鉴权限流
access_by_lua_block {
— IP 限流
local limit_req = require “resty.limit.req”
local limiter = limit_req.new(“my_limit_store”, 100, 50) — 100 req/s, burst=50
local key = ngx.var.binary_remote_addr
local delay, err = limiter:incoming(key, true)
if not delay then
if err == “rejected” then
ngx.exit(429)
end
ngx.exit(500)
end
— JWT 验证
local jwt = require “resty.jwt”
local auth_header = ngx.req.get_headers()[“Authorization”]
if auth_header then
local token = auth_header:match(“Bearer%s+(.+)”)
if token then
local jwt_obj = jwt:verify(“your-secret-key”, token)
if not jwt_obj.verified then
ngx.exit(401)
end
end
end
}
# 3. 内容生成
content_by_lua_block {
— 缓存查询
local cache = ngx.shared.my_cache
local cache_key = “api:” .. ngx.var.request_uri
local cached = cache:get(cache_key)
if cached then
ngx.say(cached)
return
end
— 业务逻辑处理
local response = {
status = “success”,
data = { message = “API Response” },
timestamp = os.date(“%Y-%m-%dT%H:%M:%S”)
}
local cjson = require “cjson”
local json_response = cjson.encode(response)
— 写入缓存(10秒过期)
cache:set(cache_key, json_response, 10)
ngx.header[“Content-Type”] = “application/json”
ngx.say(json_response)
}
# 4. 日志记录
log_by_lua_block {
local latency = tonumber(ngx.var.request_time) or 0
ngx.log(ngx.INFO,
“API Request: “, ngx.var.request_uri,
” | Status: “, ngx.var.status,
” | Latency: “, string.format(“%.3f”, latency), “s”,
” | IP: “, ngx.var.remote_addr
)
}
}
}
}
6. 实战应用场景
6.1 API 网关实现
OpenResty 是构建高性能 API 网关的理想选择:
— lua/api_gateway.lua
local _M = {}
function _M.route_request()
local uri = ngx.var.request_uri
local method = ngx.req.get_method()
— 路由表配置
local routes = {
[“/api/v1/users”] = { upstream = “user-service”, rate_limit = 100 },
[“/api/v1/products”] = { upstream = “product-service”, rate_limit = 200 },
[“/api/v1/orders”] = { upstream = “order-service”, rate_limit = 50, auth_required = true }
}
— 查找路由
local route = routes[uri]
if not route then
ngx.exit(404)
return
}
— 鉴权检查
if route.auth_required then
local auth = require “lib.auth”
if not auth.validate_token() then
ngx.exit(401)
return
end
}
— 限流检查
local limiter = require “lib.limiter”
if not limiter.check(ngx.var.binary_remote_addr, route.rate_limit) then
ngx.exit(429)
return
end
— 请求转发
ngx.var.upstream = route.upstream
end
return _M
6.2 动态限流与熔断
— lua/rate_limiter.lua
local resty_limit_req = require “resty.limit.req”
local resty_limit_conn = require “resty.limit.conn”
local _M = {}
— 基于令牌桶算法的限流
function _M.limit_by_ip(rate, burst)
local limiter, err = resty_limit_req.new(“ip_limit_store”, rate, burst)
if not limiter then
ngx.log(ngx.ERR, “failed to create limiter: “, err)
return true — 出错时放行
end
local key = ngx.var.binary_remote_addr
local delay, err = limiter:incoming(key, true)
if not delay then
if err == “rejected” then
ngx.header[“Retry-After”] = “1”
return false
end
ngx.log(ngx.ERR, “failed to limit req: “, err)
return true
end
if delay >= 0.001 then
ngx.sleep(delay)
end
return true
end
— 并发连接数限制
function _M.limit_connections(max_conn)
local limiter, err = resty_limit_conn.new(“conn_limit_store”, max_conn, 0, 0.5)
if not limiter then
ngx.log(ngx.ERR, “failed to create connection limiter: “, err)
return true
end
local key = ngx.var.binary_remote_addr
local delay, err = limiter:incoming(key, true)
if not delay then
if err == “rejected” then
return false
end
return true
end
— 在 log_by_lua 阶段释放连接
if ngx.ctx.conn_key then
local conn = ngx.ctx.conn_key
local ok, err = limiter:leaving(conn)
if not ok then
ngx.log(ngx.ERR, “failed to record connection leaving: “, err)
end
end
ngx.ctx.conn_key = key
return true
end
return _M
6.3 Web 应用防火墙(WAF)
— lua/waf.lua
local _M = {}
local rules = {
sql_injection = {
patterns = {
“[‘\”]%s*or%s*[‘\”]”,
“union%s+select”,
“insert%s+into”,
“drop%s+table”,
“exec%s*%(“
},
action = “block”
},
xss = {
patterns = {
“<script[^>]*>”,
“javascript:”,
“onload%s*=”,
“onerror%s*=”
},
action = “block”
},
scanner = {
patterns = {
“nmap”,
“sqlmap”,
“nikto”,
“acunetix”
},
action = “block”
}
}
function _M.check_request()
local uri = ngx.var.request_uri
local args = ngx.req.get_uri_args()
local headers = ngx.req.get_headers()
— 检查 URI
for rule_name, rule in pairs(rules) do
for _, pattern in ipairs(rule.patterns) do
if uri:match(pattern) then
ngx.log(ngx.WARN, “WAF blocked: “, rule_name, ” in URI”)
if rule.action == “block” then
return false
end
end
end
end
— 检查查询参数
for key, value in pairs(args) do
if type(value) == “string” then
for rule_name, rule in pairs(rules) do
for _, pattern in ipairs(rule.patterns) do
if value:match(pattern) then
ngx.log(ngx.WARN, “WAF blocked: “, rule_name, ” in arg “, key)
if rule.action == “block” then
return false
end
end
end
end
end
end
— 检查 User-Agent
local user_agent = headers[“User-Agent”] or “”
for rule_name, rule in pairs(rules) do
if rule_name == “scanner” then
for _, pattern in ipairs(rule.patterns) do
if user_agent:lower():match(pattern:lower()) then
ngx.log(ngx.WARN, “WAF blocked: scanner detected – “, user_agent)
return false
end
end
end
end
return true
end
return _M
6.4 实时数据聚合
— lua/data_aggregator.lua
local redis = require “resty.redis”
local cjson = require “cjson”
local _M = {}
function _M.aggregate_metrics()
local red = redis:new()
local ok, err = red:connect(“127.0.0.1”, 6379)
if not ok then
ngx.log(ngx.ERR, “failed to connect to redis: “, err)
return
end
— 获取当前请求信息
local metrics = {
timestamp = ngx.now(),
uri = ngx.var.request_uri,
status = ngx.var.status,
request_time = ngx.var.request_time,
remote_addr = ngx.var.remote_addr,
http_user_agent = ngx.var.http_user_agent or “”
}
— 存储到 Redis
local key = “metrics:” .. os.date(“%Y%m%d%H”)
red:rpush(key, cjson.encode(metrics))
red:expire(key, 86400) — 24小时过期
— 更新实时统计
local counter_key = “counter:” .. metrics.uri
red:incr(counter_key)
red:expire(counter_key, 3600)
red:set_keepalive(10000, 100)
end
function _M.get_realtime_stats()
local red = redis:new()
local ok, err = red:connect(“127.0.0.1”, 6379)
if not ok then
return nil, err
end
local stats = {}
— 获取热门接口
local keys = red:keys(“counter:*”)
for _, key in ipairs(keys) do
local count = red:get(key)
local uri = key:match(“counter:(.+)”)
if uri and count then
table.insert(stats, {
uri = uri,
count = tonumber(count)
})
end
end
— 按访问量排序
table.sort(stats, function(a, b)
return a.count > b.count
end)
red:set_keepalive(10000, 100)
return stats
end
return _M
7. 性能优化建议
7.1 Lua 代码缓存
# 开发环境关闭缓存,方便调试
lua_code_cache off;
# 生产环境必须开启缓存
lua_code_cache on;
7.2 共享内存优化
# 根据业务需求合理分配共享内存
lua_shared_dict my_cache 100m; # 缓存数据
lua_shared_dict my_locks 10m; # 锁
lua_shared_dict my_limit 20m; # 限流计数器
7.3 连接池配置
— Redis 连接池配置
local redis = require “resty.redis”
local red = redis:new()
— 设置连接超时和读取超时
red:set_timeouts(1000, 1000, 1000) — 连接、发送、读取超时(毫秒)
— 使用连接池
local ok, err = red:connect(“127.0.0.1”, 6379)
if ok then
— 将连接放入连接池,最大空闲时间10秒,连接池大小100
red:set_keepalive(10000, 100)
end
7.4 避免阻塞操作
— 错误示例:阻塞 I/O
local file = io.open(“/path/to/large/file.txt”, “r”)
local content = file:read(“*a”)
file:close()
— 正确示例:使用非阻塞方式
local shell = require “resty.shell”
local ok, stdout, stderr, reason, status = shell.run([[
cat /path/to/large/file.txt
]])
7.5 JIT 编译优化
— 启用 JIT 编译优化
jit.on()
jit.opt.start(“minstitch=100”, “hotloop=10”, “hotexit=2”)
— 热点函数编译
local function hot_function(x)
return x * x + 2 * x + 1
end
— 预热 JIT
for i = 1, 10000 do
hot_function(i)
end
8. 总结
OpenResty 通过将 LuaJIT 深度集成到 Nginx 中,彻底改变了 Nginx 只能处理静态配置的局面。它赋予开发者直接在网络层编写业务逻辑的能力,实现了从”静态流量分发”到”动态业务执行”的质变。
核心优势总结:
性能卓越:继承 Nginx 的非阻塞 I/O 模型,配合 LuaJIT 的即时编译,单机可支撑 10 万以上并发连接
开发灵活:无需编写 C 模块,使用 Lua 脚本即可扩展功能,支持热加载
生态丰富:内置大量高质量的 Lua 库(lua-resty-redis、lua-resty-mysql、lua-resty-jwt 等)
应用广泛:特别适合 API 网关、实时数据处理、边缘计算、WAF 等场景
适用场景建议:
推荐使用 OpenResty:需要动态逻辑处理、实时决策、复杂鉴权、API 聚合的场景
推荐使用原生 Nginx:纯静态资源服务、简单的反向代理和负载均衡
学习资源:
官方文档:https://openresty.org/cn/
OpenResty 中文社区:https://openresty.org.cn/
GitHub 仓库:https://github.com/openresty
通过掌握 OpenResty,开发者可以在网络层实现复杂的业务逻辑,显著降低系统复杂度,提升整体性能。无论是构建高性能 API 网关,还是实现实时数据处理系统,OpenResty 都是一个值得深入学习和应用的技术选择。