Nginx静态集群实现零中断升级需分离配置热加载与二进制平滑升级:reload仅更新配置,版本/模块变更必须执行USR2+WINCH+QUIT流程;upstream无需特殊配置,但需启用keepalive并正确设置proxy_http_version和Connection头;升级须先验证新二进制兼容性,再按序发送信号。

Nginx 静态集群本身不依赖“集群配置”实现高可用,它没有内置的节点发现或状态同步机制。所谓“静态集群”,通常指 upstream 块中手动列出后端服务器(如多台应用服务器),由 Nginx 作为反向代理统一调度。要在这个架构下做到重载配置时对外零连接中断,关键不是改 upstream 写法,而是分离配置变更与二进制升级——因为 nginx -s reload(HUP)只解决配置热加载,而真正影响长连接稳定性的,是二进制版本切换是否平滑。
下面分三部分讲清实操要点:
一、明确什么情况必须用二进制平滑升级(而非 reload)
-
nginx -s reload(发 HUP 信号)能无缝更新 upstream 地址、超时、负载策略等纯配置项,但前提是 Nginx 二进制本身没变; - 如果你同时要:
- 升级 Nginx 版本(如从 1.22.0 → 1.24.0),
- 或启用新模块(如新增
ngx_http_geoip2_module), - 或修复 OpenSSL/CPU 漏洞需更换底层依赖,
→ 这些都要求替换二进制文件,此时仅 reload 不够,必须走 USR2 + WINCH + QUIT 流程,否则旧 worker 进程会因加载新模块失败而崩溃,或新旧二进制混用导致 socket 处理异常,引发连接重置。
二、静态集群场景下的平滑升级实操要点
-
upstream 配置本身无需特殊处理:只要你的
upstream app_cluster { server 10.0.1.10:8080; server 10.0.1.11:8080; }语法正确,它会在新旧 master 启动时被完整继承,新 worker 和旧 worker 使用同一份 upstream 定义; -
真正的风险点在连接保持环节:
- 客户端到 Nginx 的连接(如 HTTPS keep-alive、HTTP/2 stream、WebSocket)由旧 worker 继续服务,直到自然关闭;
- Nginx 到后端的连接(upstream keepalive)默认由每个 worker 独立维护,新 worker 会新建连接池,但不会中断旧 worker 正在使用的连接;
- 所以你只需确保:
- 新二进制编译时启用
--with-http_upstream_keepalive_module(1.19+ 已内置); - upstream 块中显式配置连接复用:
upstream app_cluster { server 10.0.1.10:8080; server 10.0.1.11:8080; keepalive 32; # 每个 worker 最多保持 32 个空闲连接 } - 对应 location 中启用:
proxy_http_version 1.1; proxy_set_header Connection '';
- 新二进制编译时启用
三、升级流程必须和静态集群部署协同
-
不要在 reload 同时覆盖二进制:先完成
nginx -t && nginx -s reload应用新 upstream 配置;确认无误后,再单独执行二进制平滑升级; -
升级前验证新二进制兼容性:
- 用新二进制直接测试配置:
/path/to/nginx.new -t -c /etc/nginx/nginx.conf - 检查 upstream 是否解析正常:
/path/to/nginx.new -T -c /etc/nginx/nginx.conf 2>&1 | grep app_cluster
- 用新二进制直接测试配置:
-
信号发送顺序不能错:
-
kill -USR2 $(cat /var/run/nginx.pid)→ 启动新 master(带新二进制 + 当前配置) -
kill -WINCH $(cat /var/run/nginx.pid)→ 旧 master 关闭其 worker(不影响已建立的客户端连接,也不中断正在跑的 upstream 请求) -
kill -QUIT $(cat /var/run/nginx.pid.oldbin)→ 旧 master 退出(此时所有旧 worker 已终止)
-
整个过程里,upstream 列表始终一致,客户端 TCP 连接不重置,后端服务无感知,真正实现对外零中断。
不复杂但容易忽略


















