nginx通过多进程模型与USR2/WINCH/QUIT信号实现零停机升级:旧工作进程持续处理存量连接,新主进程启动新工作进程接管新连接,全程客户端无感知。

Nginx 通过多进程模型和信号机制实现零停机时间(zero-downtime)在线升级,核心在于“平滑替换主进程”,而非重启整个服务。升级时旧工作进程持续处理已有连接,新工作进程逐步接管新连接,整个过程对客户端完全透明。
理解 Nginx 的多进程架构
Nginx 启动后由一个主进程(master process)和多个工作进程(worker processes)组成。主进程不处理网络请求,只负责管理配置加载、日志轮转、工作进程启停与监控;工作进程才是真正接收和响应请求的实体,彼此独立、无状态、可并行运行。
这种分离设计是实现热升级的前提:主进程可以被新版本替换,而正在运行的工作进程不受影响,继续完成已建立连接的请求(包括长连接、上传中请求等)。
执行在线升级的关键步骤
假设你已编译好新版 nginx 二进制文件(如 /usr/local/nginx/sbin/nginx-new),当前运行的是旧版(如 /usr/local/nginx/sbin/nginx):
- 将新二进制文件复制到原位置(或重命名后替换),确保权限和属主一致(如
root:root,且有执行权限) - 向当前主进程发送
USR2信号:
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
此时,旧主进程会启动一个新的主进程(使用新版二进制),两个主进程共存 - 新主进程启动其工作进程,开始接受新连接;旧主进程及其工作进程仍处理存量连接
- 确认新进程运行正常(检查
ps aux | grep nginx、访问测试、日志无报错)后,向旧主进程发送WINCH信号:
kill -WINCH `cat /usr/local/nginx/logs/nginx.pid`
这会让旧主进程优雅关闭其所有工作进程(不再接受新请求,但完成当前请求) - 最后,向旧主进程发送
QUIT信号退出它:
kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`
(注意:此时旧主进程 PID 已写入nginx.pid.oldbin)
升级中需关注的细节
零停机不是自动发生的,依赖正确操作和配置保障:
- 工作进程必须启用优雅关闭:确保
worker_shutdown_timeout设置合理(如30s),避免大文件上传等长时间请求被强制中断 - 共享内存与状态兼容性:若使用
limit_req、ssl_session_cache或第三方模块的共享内存,新旧版本必须 ABI 兼容;否则需在升级前清空相关缓存或接受短时状态丢失 - 配置文件兼容性:新版 nginx 可能弃用某些指令,升级前务必用
nginx -t -c /path/to/nginx.conf验证配置语法和语义 - 日志文件句柄继承:新旧主进程会同时写入同一日志文件(靠内核文件偏移保证不覆盖),但 logrotate 等工具需配置
copytruncate或配合USR1信号重开日志,避免日志丢失
验证与回滚方案
升级完成后,应立即验证:
- 用
nginx -V确认运行的是新版二进制 - 检查
ps aux | grep nginx中仅剩新主进程及其 worker,无残留旧进程 - 发起并发请求并观察响应头、TLS 版本、错误率等是否符合预期
- 若异常,可立刻用旧二进制覆盖,并向仍在运行的旧主进程(PID 在
.oldbin文件中)发送HUP重新加载配置,或直接QUIT后用旧版重启
真正的零停机能力,来自设计上的进程解耦与信号驱动,而不是魔法——只要流程清晰、验证到位,升级就能安静完成。