学习Nginx(四):平滑升级与回滚

前言

Nginx的平滑升级是指在不停掉老进程的情况下,启动新进程,并逐步将请求切换到新进程上,从而实现无缝升级。

在进行Nginx平滑升级之前,仔细阅读Nginx的官方文档和升级指南,根据实际情况进行操作。建议在测试环境中进行充分的测试,确保升级过程的稳定性和可靠性。

源码编译方式

1. 备份

备份当前的Nginx配置文件和数据,以防止在升级过程中发生意外情况导致数据丢失。

复制代码
# 编译安装目录
[root@RockyLinux9 ~]# ll /usr/local/nginx/
total 4
drwxr-xr-x. 2 nginx nginx 4096 May 11 13:43 conf
drwxr-xr-x. 2 nginx nginx   40 May 11 13:42 html
drwxr-xr-x. 2 nginx nginx    6 May 11 13:42 logs
drwxr-xr-x. 2 nginx nginx   19 May 11 13:42 sbin


# 备份
tar czvf /opt/nginx-backup-$(date +%Y%m%d-%H-%M-%S).tar.gz /usr/local/nginx/

2. 下载新版本

从Nginx官方网站下载最新版本的Nginx源码包。

复制代码
[root@RockyLinux9 ~]# curl -O https://nginx.org/download/nginx-1.26.0.tar.gz

3. 解压和编译

解压下载的源码包,并进入源码目录。根据之前的编译参数(可以通过nginx -V命令查看),使用相同的参数重新编译新版本Nginx。注意,在编译时不要使用make install命令安装,因为这会覆盖旧版本的Nginx。

复制代码
# 查看已安装版本及依赖项
[root@RockyLinux9 nginx-1.24.0]# nginx -V
nginx version: nginx/1.24.0
built by gcc 11.4.1 20231218 (Red Hat 11.4.1-3) (GCC)
built with OpenSSL 3.0.7 1 Nov 2022
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module


# 解压
[root@RockyLinux9 ~]# tar xf nginx-1.26.0.tar.gz
[root@RockyLinux9 ~]# cd nginx-1.26.0


# 编译
[root@RockyLinux9 nginx-1.26.0]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module


#只执行make,会在objs目录下生成新的二进制文件
[root@RockyLinux9 nginx-1.26.0]# make
[root@RockyLinux9 nginx-1.26.0]# objs/nginx -v
nginx version: nginx/1.26.0

4. 替换二进制文件

将编译好的新版本Nginx的二进制文件替换旧版本的二进制文件。

复制代码
# 备份
[root@RockyLinux9 nginx-1.26.0]# mv /usr/local/nginx/sbin/nginx{,.old}


# 拷贝文件
[root@RockyLinux9 nginx-1.26.0]# cp objs/nginx /usr/local/nginx/sbin/
[root@RockyLinux9 nginx-1.26.0]# chown nginx:nginx /usr/local/nginx/sbin/nginx
[root@RockyLinux9 nginx-1.26.0]# ll /usr/local/nginx/sbin/
total 11168
-rwxr-xr-x. 1 nginx nginx 5753480 May 11 17:10 nginx
-rwxr-xr-x. 1 nginx nginx 5678264 May 11 13:42 nginx.old

5. 发送USR2信号

向旧版本的Nginx主进程发送USR2信号。Nginx主进程在接收到USR2信号后,会启动一个新的Nginx主进程(使用新版本的二进制文件),并继续处理当前的请求。同时,旧的主进程会变为守护进程,不再接受新的请求,但会继续处理当前已连接的请求。

复制代码
#查看进程,仍为老版本的进程
[root@RockyLinux9 nginx-1.26.0]# ps auxf|grep nginx
root        4704  0.0  0.0   9924  2052 ?        Ss   17:09   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx       4705  0.0  0.1  14200  5252 ?        S    17:09   0:00  \_ nginx: worker process
nginx       4706  0.0  0.1  14200  5252 ?        S    17:09   0:00  \_ nginx: worker process


[root@RockyLinux9 nginx-1.26.0]# curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.24.0


# 发送USR2信号
[root@RockyLinux9 nginx-1.26.0]# kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`


# 生成了新的master进程和两个worker进程
[root@RockyLinux9 nginx-1.26.0]# ps auxf|grep nginx
root        4704  0.0  0.0   9924  2436 ?        Ss   17:09   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx       4705  0.0  0.1  14200  5252 ?        S    17:09   0:00  \_ nginx: worker process
nginx       4706  0.0  0.1  14200  5252 ?        S    17:09   0:00  \_ nginx: worker process
root        4725  0.0  0.1   9932  6528 ?        S    17:11   0:00  \_ nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx       4726  0.0  0.1  14208  4996 ?        S    17:11   0:00      \_ nginx: worker process
nginx       4727  0.0  0.1  14208  4996 ?        S    17:11   0:00      \_ nginx: worker process

5.1. 报错日志如下:发送USR2信号后,未生成新的master进程

复制代码
# cat /usr/local/nginx/logs/error.log
[alert] 55522#0: execve() failed while executing new binary process "nginx" (2: No such file or directory)

5.2. 原因:因启动时使用nginx(软链接指向/usr/sbin目录)命令启动,而非绝对路径(/usr/local/nginx/sbin/nginx)文件

5.3. 处理:结束原有进程,以服务方式启动

复制代码
[root@RockyLinux9 nginx-1.26.0]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
# or
[root@RockyLinux9 nginx-1.26.0]# systemctl start nginx

6. 发送WINCH信号

等待一段时间,确保新版本的Nginx主进程已经启动并稳定运行后,向旧的主进程发送WINCH信号。旧的主进程在接收到WINCH信号后,会逐步关闭其下的工作进程(worker process),并将连接平滑地转移到新的主进程上。

复制代码
# 生成了新的PID文件
[root@RockyLinux9 nginx-1.26.0]# ll /usr/local/nginx/logs/
total 20
-rw-r--r--. 1 root root 4719 May 11 17:26 access.log
-rw-r--r--. 1 root root 2823 May 11 17:26 error.log
-rw-r--r--. 1 root root    5 May 11 17:11 nginx.pid
-rw-r--r--. 1 root root    5 May 11 17:09 nginx.pid.oldbin


# 发送WINCH信号
[root@RockyLinux9 nginx-1.26.0]# kill -WINCH `cat /usr/local/nginx/logs/nginx.pid.oldbin`


# 旧的worker进程已经没有了
# 若此时有占用的worker进程,会处于等待关闭状态,待当前任务结束后关闭
[root@RockyLinux9 nginx-1.26.0]# ps auxf|grep nginx
root        4704  0.0  0.0   9924  2436 ?        Ss   17:09   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
root        4725  0.0  0.1   9932  6528 ?        S    17:11   0:00  \_ nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx       4726  0.0  0.1  14208  4996 ?        S    17:11   0:00      \_ nginx: worker process
nginx       4727  0.0  0.1  14208  4996 ?        S    17:11   0:00      \_ nginx: worker proces

7. 验证新版本

检查新版本的Nginx是否正常运行,并验证配置文件是否生效。可以通过查看Nginx的日志文件或使用nginx -t命令来验证配置文件的正确性。

复制代码
[root@RockyLinux9 nginx-1.26.0]# nginx -v
nginx version: nginx/1.26.0


#查看新的连接已使用新版本来响应了
[root@RockyLinux9 nginx-1.26.0]# curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.26.0

8. 发送QUIT信号

在对升级后的服务观察一段时间后,确认业务没有问题,发送QUIT信号,结束旧的master进程。

复制代码
[root@RockyLinux9 nginx-1.26.0]# kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`
[root@RockyLinux9 nginx-1.26.0]# ps auxf|grep nginx
root        4725  0.0  0.1   9932  6528 ?        S    17:11   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx       4726  0.0  0.1  14208  5380 ?        S    17:11   0:00  \_ nginx: worker process
nginx       4727  0.0  0.1  14208  5252 ?        S    17:11   0:00  \_ nginx: worker process

9. 回滚

如果在升级过程中遇到问题或新版本Nginx无法正常工作,可以进行回滚操作来恢复到旧版本的Nginx。

此操作需要在上一步:发送QUIT信号之前操作。

复制代码
#此时的进程情况
[root@RockyLinux9 nginx-1.26.0]# ps auxf|grep nginx
root        4704  0.0  0.0   9924  2436 ?        Ss   17:34   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
root        4725  0.0  0.1   9932  6528 ?        S    17:37   0:00  \_ nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx       4726  0.0  0.1  14208  4996 ?        S    17:37   0:00      \_ nginx: worker process
nginx       4727  0.0  0.1  14208  4996 ?        S    17:37   0:00      \_ nginx: worker process


# 发现业务出现问,需要进行回滚操作
# 恢复原二进制文件
[root@RockyLinux9 nginx-1.26.0]# mv /usr/local/nginx/sbin/nginx{.old,}
mv: overwrite '/usr/local/nginx/sbin/nginx'? y


[root@RockyLinux9 nginx-1.26.0]# ll /usr/local/nginx/sbin/
total 5548
-rwxr-xr-x. 1 nginx nginx 5678264 May 11 13:42 nginx


# 查看二进制程序版本
[root@RockyLinux9 nginx-1.26.0]# nginx -v
nginx version: nginx/1.24.0


# 检查配置文件
[root@RockyLinux9 nginx-1.26.0]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful


# 发送HUP信号,启用旧master的worker进程
[root@RockyLinux9 nginx-1.26.0]# kill -HUP `cat /usr/local/nginx/logs/nginx.pid.oldbin`
[root@RockyLinux9 nginx-1.26.0]# !ps
ps auxf|grep nginx
root        4704  0.0  0.0   9924  2436 ?        Ss   17:34   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
root        4725  0.0  0.1   9932  6528 ?        S    17:37   0:00  \_ nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx       4726  0.0  0.1  14208  5380 ?        S    17:37   0:00  |   \_ nginx: worker process
nginx       4727  0.0  0.1  14208  5124 ?        S    17:37   0:00  |   \_ nginx: worker process
nginx       5007  0.0  0.1  14200  4996 ?        S    18:01   0:00  \_ nginx: worker process
nginx       5008  0.0  0.1  14200  4996 ?        S    18:01   0:00  \_ nginx: worker process


# 查看Web响应版本
[root@RockyLinux9 nginx-1.26.0]# curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.26.0


# 发送QUIT信号,退出新的master进程
[root@RockyLinux9 nginx-1.26.0]# kill -QUIT `cat /usr/local/nginx/logs/nginx.pid`
[root@RockyLinux9 nginx-1.26.0]# ps auxf|grep nginx
root        5022  0.0  0.0   6408  2176 pts/2    S+   18:08   0:00  |           \_ grep --color=auto nginx
root        4704  0.0  0.0   9924  2436 ?        Ss   17:34   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx       5007  0.0  0.1  14200  4996 ?        S    18:01   0:00  \_ nginx: worker process
nginx       5008  0.0  0.1  14200  4996 ?        S    18:01   0:00  \_ nginx: worker process


# 查看当前Web响应版本,已恢复到旧版本
[root@RockyLinux9 nginx-1.26.0]# curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.24.0

二进制包方式

在原服务通过dnf/yum等包管理器安装的Nginx,再通过此方式来升级时,不会提供平滑升级的选项,因为包管理器会进行整个包的替换,包括二进制文件、配置文件、库依赖等。这种方式会重启Nginx服务,因此不是真正的平滑升级。

如确实需要以这种方式升级Nginx服务,可以考虑以下步骤:

1.备份:备份当前的 Nginx 配置文件和数据。

2.在新机器上安装新版 Nginx:在一台与当前机器配置相似的新机器上安装最新版本的 Nginx。确保所有的库依赖都已满足,并且 Nginx 能够正常启动和运行。

3.检查配置和依赖兼容性:比较新机器和原机器上的 Nginx 配置文件,确保它们是一致的或者已根据新版本进行了必要的调整。同时,检查新版本 Nginx 所依赖的库是否与原机器上的版本兼容。

4.替换二进制文件:在确认配置和依赖兼容性后,停止原机器上的 Nginx 服务,并将新机器上的 Nginx 二进制文件复制到原机器上,替换旧的二进制文件。确保复制的文件具有正确的权限和所有权。

5.验证和测试:启动 Nginx 服务,并验证它是否正常运行。检查日志文件以确保没有错误或警告。进行必要的测试以确保新版本的 Nginx 能够正常处理请求。

6.回滚:如果在升级过程中遇到问题或新版本 Nginx 无法正常工作,您可以使用之前备份的配置文件和数据来恢复到旧版本的 Nginx。

注意: 这种手动替换二进制文件的方法存在很大的风险,并且可能会导致不可预见的问题。在生产环境中进行此类操作之前,务必在测试环境中进行充分的测试,并需要有足够的经验和资源来应对可能出现的问题。

来自: 学习Nginx(四):平滑升级与回滚

相关推荐
乘云数字DATABUFF4 天前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--6 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森6 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜7 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB8 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode9 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户03284722207010 天前
如何搭建本地yum源(上)
运维
ping某11 天前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
大树8813 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠13 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql