源码编译安装Nginx是实现热升级的前提,因其支持USR2/WINCH/QUIT信号协作机制,可让新旧主进程共存并共享端口,而yum/dnf包默认不提供该能力。

直接用 USR2 信号做 Nginx 热部署,核心不是“替换内核”,而是让新旧两个主进程共存、共享监听端口,用户请求自然过渡,全程不中断。关键在信号触发的进程协作机制,不是二进制一换就完事。
为什么必须源码编译安装?
dnf/yum 安装的 Nginx 默认不支持平滑升级所需的信号控制链路——它没有保留旧进程的生命周期管理能力,升级时会直接覆盖二进制并强制重启服务。而源码安装可自定义路径(如 /opt/nginx),所有文件集中可控,nginx.pid、配置、日志路径清晰,才能精准发信号、区分新旧进程。
- 卸载系统包:
dnf remove -y nginx - 安装编译依赖:
dnf install -y gcc-c++ pcre-devel openssl-devel zlib-devel - configure 时务必记录完整参数(用
nginx -V 2>&1 | grep "configure arguments"备份),后续编译新版本必须完全一致,否则模块或路径可能不兼容
编译新版本 + 替换二进制
新版本源码解压后,严格复用旧版 configure 参数执行 ./configure && make,**只运行到 make,不要 make install**。这能避免覆盖配置文件或日志路径。
- 备份旧二进制:
mv /opt/nginx/sbin/nginx /opt/nginx/sbin/nginx.old - 复制新二进制:
cp objs/nginx /opt/nginx/sbin/(注意是objs/下的产出,不是源码根目录的) - 验证新版语法:
/opt/nginx/sbin/nginx -t,失败立即回退,不继续下一步
USR2 启动新进程 + WINCH 优雅收尾旧进程
发送 USR2 后,旧 master 不退出,而是 fork 出一个新 master;新旧 master 的 worker 进程通过 SO_REUSEPORT 共享同一个监听 socket,谁抢到 accept 锁谁处理新连接——这就实现了请求无损分流。
- 查当前 master PID:
cat /opt/nginx/logs/nginx.pid - 发 USR2:
kill -USR2 $(cat /opt/nginx/logs/nginx.pid) - 确认双 master 运行:
ps -ef | grep nginx | grep -v grep,应看到两组 master+worker - 等新进程稳定后,给旧 master 发
WINCH:kill -WINCH $(cat /opt/nginx/logs/nginx.pid.oldbin),让它逐步关闭所有 worker(不停止 master,保留接管能力) - 最后发
QUIT给旧 master:kill -QUIT $(cat /opt/nginx/logs/nginx.pid.oldbin),彻底退出
升级失败怎么快速回滚?
整个过程不改配置、不删旧文件,回滚就是秒级操作:
- 如果新 master 启动失败或异常,直接忽略
.oldbin文件,不用发任何信号 - 若已发 USR2 但新进程有问题,立刻发
QUIT给新 master PID(即nginx.pid对应的进程),旧 master 会自动恢复全量服务 - 二进制回退:
mv /opt/nginx/sbin/nginx.old /opt/nginx/sbin/nginx,再kill -HUP重载即可
整个流程不复杂,但每一步都依赖信号语义的准确理解与执行顺序。USR2 是起点,不是全部;WINCH 和 QUIT 才真正完成切换闭环。


















