关键是用balancer_by_lua_block接管转发,结合服务发现、共享字典缓存、健康感知及业务维度选点,实现免reload的动态路由。

在分布式集群中用 Nginx + Lua 实现动态路由分发,关键是把路由决策从静态配置移入运行时,由 Lua 脚本根据实时状态(如服务发现结果、请求特征、节点健康度)决定转发目标。不依赖 reload,也不硬编码 upstream 列表,真正适配弹性扩缩与多环境共存的场景。
基于服务发现自动感知后端变化
集群节点经常上下线,靠手动维护 upstream 不现实。Lua 可定期或按需拉取注册中心数据:
- 用 lua-resty-consul 或 lua-resty-http 请求 Consul/Eureka/etcd API 获取健康实例列表
- 结果存入 lua_shared_dict(如
upstream_cache),设置 TTL(建议 10–30 秒),避免每次请求都查外部系统 - 在
balancer_by_lua_block中先查缓存;若失效或为空,可触发异步更新(注意:balancer 阶段不能阻塞,更新应放在timer_at或access_by_lua_block中预热) - 节点连续失败时,Lua 自行标记“临时下线”,跳过选择——Nginx 不自动剔除,得自己维护简易状态
按业务维度实时选点
路由不只是轮询或随机,而是结合真实业务逻辑:
-
用户级一致性路由:提取
ngx.var.arg_uid或ngx.var.cookie_token,做一致性哈希映射到固定后端,保障会话粘性 -
灰度/AB 流量切分:检查
ngx.var.http_x_release或 URL 参数env=staging,匹配不同服务组 -
接口分级调度:对
/v1/pay走高可用集群,/v1/debug转测试环境,规则可存在 Redis 中动态加载 - 健康感知降级:从共享字典读各节点最近错误率,超阈值(如 5%)则跳过;同时支持 fallback 到备用集群
用 balancer_by_lua_block 真正接管转发
这是实现动态路由最核心的一环——绕过 upstream 块,直接控制连接目标:
- 定义一个空 upstream 占位:
upstream dynamic_backend { balancer_by_lua_block { ... } } - 在 block 内调用
balancer.set_current_peer(ip, port)指定具体后端 - 必须配合
resolver指令(如resolver 8.8.8.8 valid=5s)支持 DNS 解析,尤其当后端是域名时 - proxy_pass 直接指向该 upstream 名(如
proxy_pass http://dynamic_backend),不拼接变量 URL
结合 Redis 实现规则热更新
把路由策略外置,便于运营人员调整,无需动 Nginx 配置:
- 从请求中提取服务标识:比如 Host 头(
admin.example.com → admin)、路径前缀(/user/ → user)、或 Header(X-Service: payment) - 用 resty.redis 查 Redis 中的
route:payment键,获取目标 upstream 名(如payment-v2)或 IP:Port 对 - 查缓存优先:用
ngx.shared.route_cache:get(key),未命中再查 Redis,并设短 TTL(5 秒)防雪崩 - Redis 查询失败时,必须有兜底:返回上一次有效缓存值,或 fallback 到默认 upstream(如
backend_default),不能直接报错











