nginx tcp代理实现后端平滑切换需组合被动健康检查、least_conn负载均衡、max_conns限流、动态upstream更新及长连接draining协同:启用max_fails/fail_timeout自动剔除故障节点,least_conn+max_conns缓解冷启动冲击,后端主动draining配合nginx连接保活与信号摘机,确保请求不中断、连接不丢。

在 Nginx 的 TCP 代理(即 stream 上下文)中实现后端节点平滑切换,核心难点在于:stream 模块不支持 HTTP 层的健康检查、重试、响应头解析等能力,也无法直接识别应用层就绪状态。但通过组合被动健康探测、连接复用控制、优雅摘除机制与上游协同,仍可做到请求不中断、连接不丢、故障自动规避。
启用 stream 层被动健康检查
stream 模块原生支持基于连接层面的被动探测(max_fails/fail_timeout),这是平滑切换的基础保障:
- 每个
server行必须显式配置max_fails=2 fail_timeout=15s,Nginx 在连接拒绝、超时或读写出错时计数失败,达到阈值后临时剔除该节点 - 避免设
max_fails=0或过长fail_timeout,否则故障节点会长期参与轮询,导致客户端反复超时 - 注意:stream 不支持
proxy_next_upstream,重试行为由负载均衡策略隐式决定(如least_conn会自然避开已标记为 down 的节点)
用 least_conn + 连接限流缓解冷启动冲击
TCP 服务(如 MySQL、Redis、gRPC)冷启动时,新节点常因连接池未初始化、线程未预热而拒绝连接或响应极慢。仅靠权重无法解决:
- 使用
least_conn而非round_robin,让流量天然倾向当前活跃连接更少的节点,新节点初始连接数低,自然承接较少流量 - 对新节点设置
max_conns 16(根据后端实际并发能力调整),超出连接立即排队或拒绝,防止雪崩 - 搭配
queue 32 timeout=10s缓冲瞬时洪峰,超时未被接纳的连接返回Connection refused,客户端可快速重试其他节点
配合 upstream 动态更新与信号驱动摘机
stream 模块不支持运行时修改 upstream,但可通过外部协同实现“软摘机”:
- 新增节点时,先以低权重(
weight=1)加入 upstream,执行nginx -s reload——旧 worker 继续服务存量连接,新 worker 开始分发新连接 - 下线节点前,后端主动关闭监听端口或返回 TCP RST;Nginx 在下次连接尝试失败后触发
max_fails逻辑,自动将其标记为down,无需人工干预 - 若需更精细控制(如灰度切流),可用
map指令结合$remote_addr或$binary_remote_addr实现 IP 级路由分流,再分别指向不同 upstream 块
长连接场景下的保活与 draining 协同
TCP 长连接(如数据库连接池、gRPC stream)对代理层更敏感,需两端配合:
- Nginx 侧:设置
proxy_timeout 600;(单位秒),确保空闲连接不被过早断开;同时开启proxy_responses 1;避免单次响应后关闭连接 - 后端侧:支持 draining 模式(如 MySQL 可设
super_read_only=ON拒绝写入,gRPC 服务收到SIGUSR2后停止接受新 stream,但保持已有流直至完成) - 运维侧:下线前先通知后端进入 draining,等待
netstat -ant | grep :port | wc -l接近 0 后再 reload,确保无活跃连接残留











