nginx stream模块不支持运行时修改weight,需借助nginx-upsync-module+consul/etcd实现毫秒级动态权重同步,或使用openresty 1.25.1+通过preread_by_lua_block结合共享字典做内存级选路,也可选用least_conn等内置策略替代。

Nginx 原生 stream 模块不支持运行时修改 upstream 中的 weight 参数——该值在加载配置时固化,无法像 HTTP 层那样通过 Lua 或 API 动态更新。要实现 TCP 代理下的动态权重,必须绕过静态 weight 限制,借助外部系统驱动变更并热生效。
用 nginx-upsync-module + Consul/etcd 实现毫秒级权重同步
这是目前唯一成熟、低侵入、支持 TCP 场景的动态权重方案。upsync 模块兼容 stream 块,能从 Consul 或 etcd 拉取带 weight 字段的 JSON 节点列表,自动更新 upstream 内存状态,无需 reload。
- 编译 Nginx 时需加入:
--add-module=/path/to/nginx-upsync-module --with-stream - stream 配置示例:
stream { upstream tcp_backend { upsync 127.0.0.1:8500/v1/kv/upstreams/tcp_backend/ upsync_timeout=300ms upsync_interval=300ms upsync_fallback=stale; upsync_dump_path /var/run/tcptest.conf; } server { listen 9001; proxy_pass tcp_backend; proxy_timeout 1s; } } - Consul KV 中写入格式(JSON 数组):
[{"server":"192.168.1.10:3306","weight":8,"max_fails":3},{"server":"192.168.1.11:3306","weight":4,"max_fails":3}] - 权重变更只需更新 Consul KV,Nginx 每 300ms 拉取一次,生效延迟 ≤ 500ms
用 OpenResty + Lua 在 stream 层做内存级选路(需定制开发)
标准 Nginx 不支持 stream 块中的 balancer_by_lua_block,但 OpenResty 2024+ 版本已实验性支持 preread_by_lua_block 和共享字典联动,可实现轻量闭环调控。
- 启用
lua_shared_dict缓存各节点实时指标(如连接建立耗时、健康探测延迟) - 用
ngx.timer.at定期探测后端 TCP 连通性与 handshake 延迟(如tcp_connect+sock:settimeout) - 在
preread_by_lua_block中读取共享字典,按公式计算临时权重:score = base_weight * (ref_rtt / actual_rtt) ^ 1.5,再按加权随机选节点 - 调用
balancer.set_current_peer()(需 patch 或使用 lua-upstream-nginx-module 扩展) - 注意:此方式要求 OpenResty ≥ 1.25.1,并开启
stream_ssl_preread on等配套模块
规避 weight 依赖,改用 least_conn 或 hash 策略辅助均衡
若动态权重建设成本过高,可结合 TCP 特性选择更稳健的替代策略:
-
least_conn:适用于长连接密集型服务(如数据库代理、游戏网关),Nginx 自动选择当前活跃连接数最少的后端,天然响应负载变化
upstream tcp_backend { least_conn; server 192.168.1.10:3306; server 192.168.1.11:3306; } - ip_hash / hash $remote_addr consistent:保证客户端会话粘性,避免因权重突变导致连接抖动
-
配合主动健康检查:用
ngx_stream_upstream_check_module(需编译)定期发 TCP 探针,失败节点自动摘除,比调权更能保障可用性
关键注意事项
无论采用哪种路径,都需同步做好可观测性与容错设计:
- TCP 层无
$upstream_response_time,只能靠连接建立延迟、read/write 超时、主动探活结果评估节点质量 - 避免仅凭单次探测调整权重,建议聚合 3–5 次探测结果再决策,防止网络抖动误判
- 所有外部依赖(Consul、Prometheus、探测脚本)必须高可用,否则权重失准将放大故障面
- 新节点上线建议设 fallback 权重(如 weight=2),防止冷启动时承接过多流量











