学习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(四):平滑升级与回滚

相关推荐
少妇的美梦10 小时前
logstash教程
运维
chen94511 小时前
k8s集群部署vector日志采集器
运维
chen94511 小时前
aws ec2部署harbor,使用s3存储
运维
東雪蓮☆16 小时前
深入理解 LVS-DR 模式与 Keepalived 高可用集群
linux·运维·服务器·lvs
qq_2642208916 小时前
LVS负载均衡群集和LVS+Keepalived群集
运维·负载均衡·lvs
2303_Alpha16 小时前
SpringBoot
笔记·学习
乌萨奇也要立志学C++16 小时前
【Linux】进程概念(二):进程查看与 fork 初探
linux·运维·服务器
雨落Liy16 小时前
Nginx 从入门到进阶:反向代理、负载均衡与高性能实战指南
运维·nginx·负载均衡
萘柰奈16 小时前
Unity学习----【进阶】TextMeshPro学习(三)--进阶知识点(TMP基础设置,材质球相关,两个辅助工具类)
学习·unity
沐矢羽17 小时前
Tomcat PUT方法任意写文件漏洞学习
学习·tomcat