核心是绕过静态upstream,用balancer_by_lua_block在请求处理阶段实时选点,依据用户ID、接口路径、健康状态等业务维度动态决策,并通过shared_dict缓存+异步更新保障性能与可靠性。

用 Lua 脚本定制负载均衡算法,核心是绕过 Nginx 默认的静态 upstream 机制,在请求处理关键阶段(如 balancer_by_lua_block)注入业务逻辑,实时计算并选定后端节点。它不依赖预设权重或轮询顺序,而是根据真实上下文动态决策——比如用户 ID 哈希、接口路径分级、实时健康状态或外部配置中心返回的权重。
选点时机必须精准:用 balancer_by_lua_block 替代传统 upstream
这不是在 rewrite 或 access 阶段“改个变量”就完事,而是真正接管 Nginx 的连接分发流程:
- 定义一个空 upstream 块(仅作占位),里面不写任何
server指令 - 在该 upstream 内使用
balancer_by_lua_block,调用ngx.balancer.set_current_peer(ip, port)直接指定目标地址 - proxy_pass 必须指向这个 upstream 名(如
http://dynamic_backend),Nginx 才会触发 Lua 选点逻辑 - 不能在该 block 中做同步 HTTP 请求、文件读写或 sleep —— 否则会阻塞整个 worker 进程
按业务维度写路由逻辑:常见可落地的定制方式
算法不是抽象概念,而是对应具体字段和判断条件:
-
用户一致性路由:取
ngx.var.arg_uid或ngx.var.cookie_user_id,用ngx.crc32_short()哈希后对节点数取模,确保同一用户始终打到同一台后端 -
环境/灰度分流:检查
ngx.var.http_x_env或 URL 参数env=staging,从共享字典查出 staging 组节点列表再选点 -
接口敏感度调度:匹配
ngx.var.uri,如/v2/order/pay走高 SLA 集群,/v1/debug转发到低优先级测试机 - 健康感知剔除:维护一个共享字典记录各节点最近失败次数,若超阈值则跳过选择,不等 Nginx 自带健康检查生效
状态与数据要轻量持久:善用 shared_dict 和异步更新
每次请求都去 Redis 或 Consul 拉节点列表?那不是动态,是拖慢。正确做法是:
- 用
lua_shared_dict upstream_cache 10m缓存节点列表、权重、健康标记等结构化数据 - 设置 TTL(如 30 秒),在
balancer_by_lua_block中先查缓存;若过期,不在此处拉新数据,而是触发timer_at在后台异步刷新 - 权重变更时,避免重载 Nginx 配置,直接
redis-cli hset loadbalance:weights node-a 5,Lua 脚本定时或按需 reload - 禁止用全局 table 或文件存储状态——跨 worker 不可见,且重启即丢
别忽略边界与兜底:让定制算法真正可靠
写完逻辑只是开始,健壮性决定能否上生产:
- 所有
set_current_peer调用后必须检查返回值ok,失败时应ngx.exit(503)或 fallback 到备用集群 - 节点列表为空时要有默认兜底地址(如本地 mock 服务或降级页),不能让请求卡住
- 哈希或随机选点前,务必确认节点数组非空,避免
upstreams[0]报错 - 日志级别设为
ngx.INFO记录选点结果(如 “uid=123 → 192.168.1.20:8080”),方便问题追踪,但避免高频ngx.ERR



















