Nginx 平滑升级原理分析和实验

Nginx平滑升级

  • 1. 为什么要对 Nginx 平滑升级
  • 2. 平滑升级的原理
  • 3. Nginx 信号简介
    • 3.1. master 主进程支持的信号
    • 3.2. worker 工作进程支持的信号
  • 4. Nginx 平滑升级实战
  • 5. 平滑升级总结
  • 6. 升级实验
    • 6.1. 部署一台新的 Nginx 服务器
    • 6.2. 查看版本和模块
    • 6.3. 访问验证
    • 6.4. 升级 Nginx

1. 为什么要对 Nginx 平滑升级

对Nginx进行平滑升级是为了确保服务在升级过程中不中断,保持稳定性和可用性。平滑升级的主要目的是在不影响用户访问的情况下,应用新的配置或版本,以及引入新的功能或修复安全漏洞。以下是一些理由:

  1. 无中断升级: 平滑升级可以确保在整个升级过程中不中断正在处理的请求。这对于需要提供高可用性和无缝用户体验的服务来说至关重要。
  2. 持续服务: 在升级期间,Nginx可以继续处理来自用户的请求,而不需要暂停或重启整个服务。这对于在线业务和关键应用来说是至关重要的,可以保持服务的连续性。
  3. 避免用户感知: 平滑升级可以在后台进行,对用户来说是透明的。用户不会察觉到系统正在进行升级,他们可以继续正常使用服务而不受影响。
  4. 配置无缝切换: 平滑升级允许管理员在新旧配置之间平稳过渡,确保新的配置在启用后立即生效,而不会导致服务中断。
  5. 防止请求丢失: 平滑升级通常会确保在升级过程中,已接受的请求能够被顺利完成,而不会丢失。这对于保障数据完整性和一致性非常重要。
  6. 应用新特性: 平滑升级使得可以引入新的功能或性能优化,而不会对现有服务造成负面影响。这有助于及时应用最新的技术和改进。

在实施平滑升级时,通常采用以下策略:

  • 多实例部署: 启动一个新的Nginx实例,并在新实例上进行升级测试,然后切换流量到新实例,最后停止旧实例。
  • 热重载: 使用Nginx的热重载功能,通过向主进程发送信号,实现不停止服务的情况下加载新的配置。
  • 蓝绿部署: 将新版本的Nginx部署在与旧版本相同的环境中,然后逐渐将流量从旧版本切换到新版本。

无论采用哪种策略,平滑升级都是一种最佳实践,可以确保服务的稳定性和可用性。

2. 平滑升级的原理

平滑升级的原理主要涉及到在升级过程中保持服务的连续性和稳定性。以下是平滑升级的一般原理:

  1. 多实例部署:
  • 在平滑升级中,通常会采用多实例部署的方式。新版本的 Nginx 会在一个独立的实例中启动,并与旧版本的 Nginx 并行运行。
  1. 新旧版本并行:
  • 新旧版本的 Nginx 实例会并行处理请求。这样做的目的是确保在升级过程中不中断服务,同时逐步将流量从旧版本切换到新版本。
  1. 流量切换:
  • 管理员可以逐步切换流量,将一部分请求导向新版本的 Nginx 实例。这可以通过负载均衡器、代理服务器或 DNS 修改来实现。流量逐渐过渡,直到完全切换到新版本。
  1. 配置逐步生效:
  • 新版本的 Nginx 会加载新的配置,但并不一定立即生效。管理员可以逐步应用新的配置,确保在升级过程中不会导致配置的突然变更,从而影响服务的稳定性。
  1. 请求完成:
  • 在升级过程中,已经接收的请求会继续由旧版本的 Nginx 处理,而新版本则处理新的请求。这确保了已接受的请求能够顺利完成,而不会丢失。
  1. 检测和监控:
  • 在整个升级过程中,管理员需要进行实时的监控和检测。这包括监控新旧版本的性能、错误率、日志等,以确保升级过程中没有出现异常情况。
  1. 回滚机制:
  • 如果在升级过程中发现了问题,管理员可以快速回滚到旧版本,恢复正常服务。因此,平滑升级需要提供有效的回滚机制,确保在出现意外情况时能够及时处理。
  1. 灰度发布:
  • 平滑升级的一种变体是灰度发布,其中只向部分用户或流量引入新版本。这有助于在小范围内测试新版本,发现潜在问题并及时修复。

其原理简单概括,就是:
(1)在不停掉老进程的情况下,启动新进程。
(2)老进程负责处理仍然没有处理完的请求,但不再接受处理请求。
(3)新进程接受新请求。
(4)老进程处理完所有请求,关闭所有连接后,停止。
这样就很方便地实现了平滑升级。一般有两种情况下需要升级 Nginx,一种是确实要升级 Nginx 的版本,另一种是要为 Nginx 添加新的模块
平滑升级是热升级、热部署,可以不停服务的情况对 Nginx 服务进行升级

3. Nginx 信号简介

3.1. master 主进程支持的信号

  • TERM, INT:立刻退出
  • QUIT:等待工作进程结束后再退出
  • KILL:强制终止进程
  • HUP:重新加载配置文件,使用新的配置启动工作进程,并逐步关闭旧进程。
  • USR1:重新打开日志文件
  • USR2:启动新的主进程master,实现热升级
  • WINCH:逐步关闭worker工作进程

3.2. worker 工作进程支持的信号

  • TERM, INT:立刻退出
  • QUIT:等待请求处理结束后再退出
  • USR1:重新打开日志文件

4. Nginx 平滑升级实战

将nginx1.16升级成nginx1.18
wget https://nginx.org/download/nginx-1.16.0.tar.gz
yum -y install gcc gcc-c++ pcre pcre-devel gd-devel openssl openssl-devel  zlib zlib-devel
useradd nginx && echo "nginx" | passwd --stdin nginx
mkdir /tmp/nginx
tar -xzvf nginx-1.16.0.tar.gz -C /usr/local/
cd /usr/local/nginx*

./configure 
--prefix=/usr/local/nginx 
--user=nginx 
--with-http_ssl_module 

make && make install


#将nginx托管到systemd管理(可选步骤)
vim  /usr/lib/systemd/system/nginx.service 
[Unit]
#描述服务
Description=nginx
#描述服务类别
After=network.target

#服务运行参数的设置,注意【Service】的启动、重启、停止命令都要用绝对路径
[Service]
#后台运行的形式
Type=forking
#服务具体运行的命令
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
#重启命令
ExecReload=/usr/local/nginx/sbin/nginx -s reload
#停止命令
ExecStop=/usr/local/nginx/sbin/nginx -s  stop 
#表示给服务分配独立的临时空间
PrivateTmp=true

#运行级别下服务安装的相关设置,可设置为多用户,即系统运行级别为3
[Install]
WantedBy=multi-user.target

systemctl daemon-reload
systemctl enable --now nginx
systemctl status nginx

查看现有的 nginx 编译参数

/usr/local/nginx/sbin/nginx -V

按照原来的编译参数安装 nginx 的方法进行安装
只需要到 make,千万不要 make install 。如果 make install 会将原来的配置文件覆盖

#下载nginx1.18版本
wget https://nginx.org/download/nginx-1.18.0.tar.gz

tar -xzvf nginx-1.18.0.tar.gz -C /usr/local/

cd /usr/local/nginx-1.18.0/

./configure 
--prefix=/usr/local/nginx 
--user=nginx 
--with-http_ssl_module 

make

备份原 nginx 二进制文件
备份二进制文件和 nginx 的配置文件(期间nginx不会停止服务)

mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx_$(date +%F)

复制新的nginx二进制文件,进入新的nginx源码包

cp /usr/local/nginx-1.16.0/objs/nginx /usr/local/nginx/sbin/

测试新版本的nginx是否正常

/usr/local/nginx/sbin/nginx -t

给nginx发送平滑迁移信号(若不清楚pid路径,请查看nginx配置文件)

kill -USR2 `cat /var/run/nginx.pid`

查看nginx pid,会出现一个nginx.pid.oldbin

ll /var/run/nginx.pid*
-rw-r--r-- 1 root root 5 Jul  1 11:29 /var/run/nginx.pid
-rw-r--r-- 1 root root 5 Jul  1 09:54 /var/run/nginx.pid.oldbin

从容/优雅的关闭旧的Nginx进程

kill -WINCH `cat /var/run/nginx.pid.oldbin`

结束工作进程,完成此次升级

kill -QUIT `cat /var/run/nginx.pid.oldbin`

验证Nginx是否升级成功

/usr/local/nginx/sbin/nginx -V

5. 平滑升级总结

实现的步骤:
1、首先使用nginx -V查看nginx现有的编译参数
2、然后下载好要更新的源码包,上传到服务器中,然后使用make命令编译,编译时用--with添加要使用的模快,--without去除不需要的模快
3、备份旧的nginx二进制文件,再将新编译好的二进制文件复制到/usr/local/nginx/sbin
4、备份完之后,给旧的进程发送一个kill -USR2的信号,会启动一个新的nginx主进程,实现热升级
5、然后这个时候就能发现/var/run/nginx/pid下会出现两个进程(nginx.pidnginx.pid.oldbin
6、再给旧的nginx进程发送一个kill -WINCH的信号,让旧的nginx work进程从容关闭,不再接受新请求
7、然后发送一个kill -QUIT的信号,让旧的nginx主进程处理完请求后再退出
8、最后再查看nginx的版本,是否升级成功

6. 升级实验

6.1. 部署一台新的 Nginx 服务器

安装配置1.6版本的 nginx,重新开启一台机器

[root@localhost ~]# yum install -y gcc gcc-c++ pcre-devel openssl-devel zlib-devel
[root@localhost ~]# tar xzf nginx-1.6.3.tar.gz -C /usr/local/
[root@localhost ~]# cd /usr/local/nginx-1.6.3
[root@localhost nginx-1.6.3]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module
[root@localhost nginx-1.6.3]# make && make install
[root@localhost nginx-1.6.3]# useradd -M -s /sbin/nologin nginx
[root@localhost nginx-1.6.3]# /usr/local/nginx/sbin/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
[root@localhost nginx-1.6.3]# /usr/local/nginx/sbin/nginx 
[root@localhost nginx-1.6.3]# netstat -lntp
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      13989/nginx: master

6.2. 查看版本和模块

[root@localhost nginx-1.6.3]# /usr/local/nginx/sbin/nginx -V 
nginx version: nginx/1.6.3
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) 
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module
[root@localhost nginx-1.6.3]# echo "nginx1.6" > /usr/local/nginx/html/index.html
[root@localhost nginx-1.6.3]# yum install -y elinks

6.3. 访问验证

[root@localhost nginx-1.6.3]# elinks -dump 192.168.221.138

6.4. 升级 Nginx

将 nginx 版本进行升级 并在不影响业务的情况下添加 SSL 和 pcre 模块

[root@localhost ~]# tar xzf nginx-1.12.2.tar.gz -C /usr/local/
[root@localhost ~]# cd /usr/local/nginx-1.12.2/
[root@localhost nginx-1.12.2]# ./configure --prefix=/usr/local/nginx --user=nginx --group=ngiinx --with-http_stub_status_module --with-http_ssl_module --with-pcre
[root@localhost nginx-1.12.2]# make
[root@localhost nginx-1.12.2]# cd
[root@localhost ~]# mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx_lod
[root@localhost ~]# cp /usr/local/nginx-1.12.2/objs/nginx /usr/local/nginx/sbin/
[root@localhost ~]# kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`