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

相关推荐
AI-Ming1 分钟前
程序员转行学习 AI 大模型: 踩坑记录:服务器内存不够,程序被killed
服务器·人工智能·python·gpt·深度学习·学习·agi
m0_716765234 分钟前
C++提高编程--STL常用容器(set/multiset、map/multimap容器)详解
java·开发语言·c++·经验分享·学习·青少年编程·visual studio
2501_945318497 分钟前
零基础学习AI的选型指南:CAIE认证与编程型AI认证如何取舍
人工智能·学习
承渊政道11 分钟前
【优选算法】(实战推演模拟算法的蕴含深意)
数据结构·c++·笔记·学习·算法·leetcode·排序算法
yj_xqj21 分钟前
HAproxy负载均衡集群部署
运维·负载均衡
路由侠内网穿透23 分钟前
本地部署开源工作空间工具 AFFiNE 并实现外部访问
运维·服务器·数据库·物联网·开源
zzzsde25 分钟前
【Linux】Ext文件系统(1)
linux·运维·服务器
Keep learning!26 分钟前
PCA主成分分析学习
学习·算法
爱学习的小囧27 分钟前
ESXi 8.0 无法选择分区方式 小白级详细解决办法
运维·服务器·网络·虚拟化·esxi8.0
F1FJJ31 分钟前
什么是 Shield CLI?视频讲解:一条命令,可浏览器远程访问一切内部服务(RDP/VNC/SSH/数据库等)
运维·网络·数据库·网络协议·ssh