如何在不停止服务的情况下,对 Nginx 进行热升级(平滑升级)?
对 Nginx 进行不中断服务的平滑升级(热升级),是 Nginx 核心架构(Master-Worker 进程模型)带来的一项非常实用的特性。
整个过程的核心思想是:启动新的 Nginx Master 进程 -> 让新进程接管请求 -> 优雅地关闭旧 Worker 进程 -> 关闭旧 Master 进程。
以下是详细的操作步骤:
核心信号说明
在开始前,你需要了解几个关键的 Nginx 信号:
USR2:平滑升级可执行程序。告诉旧 Master 进程,准备升级。WINCH:优雅地关闭 Worker 进程。QUIT:优雅地关闭 Master 进程。HUP:重新加载配置文件(在回滚时会用到)。
第一步:准备新版本的 Nginx
查看当前版本和编译参数
记录下当前的编译参数,保证新版本拥有相同的模块。bash/usr/local/nginx/sbin/nginx -V注意输出的
configure arguments:后面的内容并复制下来。下载并解压新版本源码
bashwget http://nginx.org/download/nginx-1.x.x.tar.gz tar -zxvf nginx-1.x.x.tar.gz cd nginx-1.x.x配置和编译
使用第一步复制的configure arguments进行配置。bash./configure [你的旧编译参数]然后进行编译:
bashmake⚠️ 极其重要:绝对不要执行
make install,否则会覆盖现有的配置文件和目录!
第二步:替换 Nginx 二进制文件
备份旧的二进制文件
bashmv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old拷贝新的二进制文件到 sbin 目录
在刚刚编译的源码目录下(objs目录中存放着新编译的二进制文件):bashcp objs/nginx /usr/local/nginx/sbin/nginx测试新二进制文件与旧配置的兼容性
bash/usr/local/nginx/sbin/nginx -t确保输出
syntax is ok和test is successful。
第三步:发送信号进行平滑升级
查找当前(旧)Nginx 的 Master 进程 PID
bashps -ef | grep nginx或者直接查看 pid 文件:
bashcat /usr/local/nginx/logs/nginx.pid假设查到的旧 Master PID 是
1111。发送
USR2信号:启动新 Master 进程bashkill -USR2 1111此时系统会发生以下事情:
- 旧 Nginx 会将当前的
.pid文件重命名为.pid.oldbin。 - 旧 Nginx 会使用新的二进制文件启动一个新的 Master 进程(假设 PID 为
2222)和新的 Worker 进程。 - 此时,新旧 Nginx 同时运行,共同处理请求。
- 旧 Nginx 会将当前的
发送
WINCH信号:优雅关闭旧 Worker 进程bashkill -WINCH 1111此时系统会发生以下事情:
- 旧的 Master 进程会告诉它的 Worker 进程:“处理完手头的请求后就退出”。
- 等待一段时间后,所有的旧 Worker 进程都会退出。
- 此时,只有新的 Worker 进程在处理请求,旧的 Master 进程依然存活(以防需要回滚)。
第四步:确认与收尾
观察运行状态
检查业务是否正常访问。使用ps -ef | grep nginx查看进程状态,你应该只能看到一个旧的 Master,一个新的 Master,以及新的 Worker 进程。发送
QUIT信号:关闭旧 Master 进程(最终完成升级)
如果你确信新版本运行完美,没有问题,就可以关闭旧的 Master 进程了。bashkill -QUIT 1111至此,平滑升级彻底完成。
🚨 附录:如果升级失败,如何平滑回滚?
如果在执行到 第三步的第3小步(旧 Worker 已关闭,旧 Master 还在)时,发现新版本有问题,可以按照以下步骤无损回滚:
拉起旧的 Worker 进程
发送HUP信号给旧的 Master 进程(PID:1111),它会重新启动旧的 Worker 进程。bashkill -HUP 1111优雅关闭新的 Master 进程及其 Worker
发送QUIT信号给新的 Master 进程(PID:2222)。bashkill -QUIT 2222恢复二进制文件
bashmv /usr/local/nginx/sbin/nginx.old /usr/local/nginx/sbin/nginx回滚完成。