Nginx集成Lua实现根据POST请求报文内容
Linux命令
Nginx集成Lua实现根据POST请求报文内容
2025-03-20 00:03
? Nginx+Lua动态负载策略实战指南(2024新版) 一、环境准备与模块加载 核心组件:
? Nginx+Lua动态负载策略实战指南(2024新版)
一、环境准备与模块加载
核心组件:
- OpenResty 1.25.3.1(2024最新稳定版)
- lua-resty-core 0.1.27
- lua-cjson 2.1.0.11
# 编译时添加LuaJIT支持
./configure --prefix=/usr/local/openresty \
--with-luajit \
--with-http_ssl_module \
--with-http_realip_module
二、请求体解析配置
# 在http块中全局配置
http {
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
lua_shared_dict request_cache 10m; # 共享内存缓存
# 启用请求体读取
client_body_buffer_size 128k;
client_max_body_size 10m;
}
三、动态负载策略实现
1. 主服务配置
server {
listen 80;
# 仅处理POST请求
location /api {
access_by_lua_block {
-- ?️ 关键步骤:读取并解析请求体
ngx.req.read_body()
local body_data = ngx.req.get_body_data()
if not body_data then
ngx.log(ngx.ERR, "Empty request body")
return ngx.exit(400)
end
-- 解析JSON数据
local cjson = require "cjson.safe"
local req_obj = cjson.decode(body_data)
if not req_obj then
ngx.log(ngx.ERR, "JSON decode failed")
return ngx.exit(400)
end
-- ? 根据业务字段生成哈希键
local routing_key = req_obj.user_id or req_obj.device_id
if not routing_key then
ngx.log(ngx.WARN, "Missing routing key")
return ngx.exit(403)
end
-- 存储到共享变量
ngx.ctx.backend_key = ngx.crc32_long(routing_key) % 4
}
proxy_pass http://dynamic_backend;
}
}
2. 动态upstream配置
upstream dynamic_backend {
balancer_by_lua_block {
-- ? 负载决策核心逻辑
local balancer = require "ngx.balancer"
local backend_key = ngx.ctx.backend_key
-- 后端服务器列表
local backends = {
"10.0.1.10:8080", -- 0号节点
"10.0.1.11:8080", -- 1号节点
"10.0.1.12:8080", -- 2号节点
"10.0.1.13:8080" -- 3号节点
}
-- 加权轮询扩展(示例)
local weights = {30, 20, 20, 30} -- 总权重100
local total = 0
local rand = ngx.now() % 100
for i=1, #weights do
total = total + weights[i]
if rand < total then
backend_key = i-1
break
end
end
-- 设置目标后端
local ok, err = balancer.set_current_peer(
backends[backend_key + 1])
if not ok then
ngx.log(ngx.ERR, "Balancer error: ", err)
return ngx.exit(500)
end
}
}
四、动态路由策略扩展
1. 基于业务类型分流
-- 在access阶段添加判断
if req_obj.biz_type == "VIP" then
ngx.ctx.backend_group = "vip_cluster"
elseif req_obj.amount > 10000 then
ngx.ctx.backend_group = "finance_cluster"
else
ngx.ctx.backend_group = "default_cluster"
end
2. 多级哈希策略
local hash1 = ngx.crc32_long(routing_key)
local hash2 = ngx.crc32_short(routing_key)
local combined_hash = bit.bxor(hash1, hash2)
ngx.ctx.backend_key = combined_hash % 8
五、性能优化要点
# 1. 缓存解析结果
set $cache_key "";
access_by_lua_block {
local key = ngx.md5(ngx.var.request_body)
local cache = ngx.shared.request_cache
local cached = cache:get(key)
if cached then
ngx.var.cache_key = cached
else
-- 解析逻辑...
cache:set(key, routing_key, 60) -- 缓存60秒
end
}
# 2. 限制请求体处理
client_body_buffer_size 128k; # 超过部分写入磁盘
lua_need_request_body on; # 按需读取
# 3. 开启协程池
lua_socket_pool_size 30;
lua_socket_keepalive_timeout 60s;
六、调试与监控
1. 日志记录配置
log_by_lua_block {
local latency = tonumber(ngx.var.upstream_response_time)
ngx.log(ngx.INFO,
"Backend:", ngx.var.upstream_addr,
" | Key:", ngx.ctx.backend_key,
" | Latency:", latency)
}
2. 实时监控命令
# 查看负载分布
tail -f /var/log/nginx/access.log | awk '{print $NF}'
# 内存使用监控
watch -n 1 "echo 'cache stats' && /usr/local/openresty/luajit/bin/resty --shdict='request_cache' /tmp/dump.lua"
七、安全防护措施
# 1. 请求体大小限制
client_max_body_size 2m; # 根据业务需求调整
# 2. 请求频率限制
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
# 3. 防SQL注入过滤
access_by_lua_block {
if ngx.re.match(body_data, [[\b(union|select|sleep)\b]]) then
ngx.exit(403)
end
}
? 生产环境注意事项:
- 灰度发布时先开启
lua_code_cache off
调试- 使用
resty-cli
工具进行热更新- 压力测试推荐使用
wrk -t12 -c400 -d30s
- 重要业务建议采用双活架构设计
- 定期检查共享内存使用率(通过
ngx.shared.DICT.stats
)
标签:
- Nginx
- Lua
- POST