nginx+lua动态负载均衡核心是用balancer_by_lua_block接管选点逻辑,绕过静态upstream;需openresty或编译启用ngx_http_lua_module,通过共享字典、cosocket调用及业务维度(用户标识、接口分级、健康感知、权重调整)实现实时决策,要求轻量无阻塞。

利用 Nginx 结合 Lua 实现动态负载均衡,核心在于绕过静态 upstream 配置,由 Lua 在请求处理阶段实时决策后端节点。这适用于灰度发布、用户分组路由、接口级权重调整、故障自动摘除等场景。
前置条件与模块准备
确保 Nginx 编译时已启用 ngx_http_lua_module(推荐使用 OpenResty,开箱即用)。不支持原生 Nginx 的 --add-module 方式动态加载 Lua 模块。检查是否可用:
nginx -V 2>&1 | grep -o 'lua'若无输出,需换用 OpenResty 或重新编译。同时建议启用 lua_shared_dict 用于跨请求共享状态(如节点健康信息)。
用 Lua 替代 upstream 实现动态选点
不再依赖 upstream {...} 块,而是用 balancer_by_lua* 钩子接管负载逻辑。该阶段在 rewrite 和 access 之后、proxy_pass 之前执行,可读取变量、调用 Lua 函数、修改 $backend_host 和 $backend_port 等变量供后续 proxy_pass 使用。
示例配置片段:
location /api/ {balancer_by_lua_block {
local balancer = require "ngx.balancer"
local host, port = "192.168.1.10", 8080
if ngx.var.arg_uid and tonumber(ngx.var.arg_uid) % 10 == 0 then
host, port = "192.168.1.11", 8080
end
local ok, err = balancer.set_current_peer(host, port)
if not ok then
ngx.log(ngx.ERR, "failed to set peer: ", err)
return ngx.exit(500)
end
}
proxy_pass http://127.0.0.1; # 占位,实际由 balancer_by_lua 决定目标
}
结合业务逻辑做真实决策
常见业务维度包括:
- 用户标识路由:解析 cookie、token 或 URL 参数(如 uid、tenant_id),哈希后映射到固定后端,保障会话一致性
-
接口分级调度:根据
ngx.var.uri或ngx.var.request_method匹配规则,将 /v1/pay 转给高可用集群,/v1/test 转给预发环境 -
实时健康感知:从
lua_shared_dict读取各节点最近 30 秒错误率,跳过 >5% 的节点;或调用本地 HTTP 接口查询注册中心状态(注意超时和降级) - 权重动态调整:基于节点 CPU/内存指标(通过 agent 上报到 Redis 或本地共享字典),按比例分配请求流量
关键注意事项
balancer_by_lua* 运行在 Nginx worker 进程中,必须保证轻量、无阻塞:
- 禁止使用
os.time()、io.open()、ngx.sleep()等阻塞调用 - HTTP 外部调用请用 cosocket(如 resty.http)并设严格 timeout(建议 ≤ 50ms)
- 共享字典读写加锁(
shdict:get_lock)仅在必要时使用,避免争抢 - 错误处理要完备:set_current_peer 失败需明确响应,否则可能触发默认 upstream 行为
不复杂但容易忽略。











