Nginx可通过USR2、WINCH、QUIT三步信号实现零停机在线升级:先启动新master与worker,再优雅关闭旧worker,最后终止旧master;全程不中断请求、不丢连接。

Nginx 本身不支持“热升级”二进制文件(即替换 nginx 可执行文件后自动加载新版本),但通过其多进程模型与信号机制,配合运维操作,可实现零停机在线升级——也就是在不中断任何正在处理的请求、不丢弃连接的前提下,平滑切换到新版本的 nginx 二进制和配置。
理解 Nginx 的多进程架构是前提
Nginx 启动后,会创建一个主进程(master process)和多个工作进程(worker processes)。主进程负责读取配置、管理 worker、接收信号;worker 进程实际处理网络请求。二者职责分离,使得升级时可以“换人不换岗”:
- 主进程可被新版本替代并重新加载,而旧 worker 仍继续服务已有连接
- 新 worker 启动后接管新连接,旧 worker 在完成当前请求后优雅退出
- 整个过程无 listen socket 关闭、无连接重置、无 502/503
升级前准备:编译新版本并保留旧二进制
关键不是“覆盖安装”,而是并行部署:
- 下载并编译新版本 nginx(如从 1.22.1 升级到 1.24.0),指定
--prefix为相同安装路径(如/usr/local/nginx),但不要执行 make install 覆盖 - 将新编译出的
objs/nginx二进制文件手动拷贝为带版本或时间戳的名称,例如:cp objs/nginx /usr/local/nginx/sbin/nginx-1.24.0 - 确认旧版本二进制仍在原位(如
/usr/local/nginx/sbin/nginx),且新旧版本配置兼容(建议先用-t测试新配置)
执行平滑升级:替换二进制 + 发送信号
假设新二进制已就位,且配置无误,按以下顺序操作:
- 将新二进制软链接或重命名为原路径(推荐先备份再替换):
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx-1.22.1<br>ln -sf /usr/local/nginx/sbin/nginx-1.24.0 /usr/local/nginx/sbin/nginx
- 向当前 master 进程发送
USR2信号,触发启动新 master + 新 worker:kill -USR2 $(cat /usr/local/nginx/logs/nginx.pid)
此时系统中会同时存在两组进程:旧 master + 旧 worker,以及新 master + 新 worker - 向旧 master发送
WINCH信号,通知它逐步关闭所有旧 worker:kill -WINCH $(cat /usr/local/nginx/logs/nginx.pid)
旧 worker 进入 graceful shutdown 状态,不再接受新连接,但继续处理完已有请求 - 确认旧 worker 全部退出后(
ps aux | grep nginx中只剩新 master 和新 worker),向旧 master 发送QUIT信号彻底终止它:kill -QUIT $(cat /usr/local/nginx/logs/nginx.pid.oldbin)
验证与回滚:确保可靠与可逆
升级不是终点,验证和兜底同样重要:
- 检查进程列表:
ps aux | grep nginx应只显示新版本 master 和 worker,且 PID 已更新 - 验证服务可用性:curl 请求、查看 access.log、检查 SSL/TLS 握手、长连接保持等
- 确认新版本功能正常(如新增模块、header 处理、限流逻辑等)
- 若异常,立即回滚:
恢复原 nginx 二进制软链接 → 向新 master 发送QUIT→ 启动旧 master(/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf)
整个过程依赖 Nginx 对信号的精确响应,不依赖外部工具,也不需要 reload 配置本身。只要操作节奏得当,用户完全感知不到服务切换。核心在于:用 USR2 启新、WINCH 收旧、QUIT 清场——三步信号,完成一次真正意义上的零停机升级。










