前言
环境:
centos7.9、源码编译安装的nginx
nginx支持的kill信号
我们源码编译安装的
nginx
,通过直接执行
/usr/local/nginx/sbin/nginx
来启动
nginx
,其中停止,退出,重开日志,重载配置是通过
/usr/local/nginx/sbin/nginx -s stop|quit|reopen|reload
来发送信息给
master
进程实现的。除了这种方式,官方说明文档显示还提供
kill
命令来发送对应的信号给
nginx
主进程,
nginx
的
master
进程接收到这些信号就会执行对应的操作,如下:
kill 命令传送信号给nginx的master进程,注意是发送给master进程,不是worker进程:
TERM、INIT :强制退出,当前的请求不执行完成就退出 等介于 ./nginx -s stop
QUIT :优雅退出,等待请求执行完成后退出 等介于 ./nginx -s quit
HUP :重载配置文件,用新的配置文件启动新的work进程并优雅的关闭旧的work进程,等介于./nginx -s reload
USR1 :重开日志,等价于./nginx -s reopen
USR2 :平滑的升级nginx,拉起一个新的nginx主进程,同时做到不停止旧的nginx主进程
WINCH :优雅的关闭worker进程,发送一个WINCH信号给master进程,告知其优雅的关闭worker进程
演示示例:
kill -TERM 195916 #强制停止nginx,等价于 ./nginx -s stop
kill -INT 197019 #强制停止nginx,等价于 ./nginx -s stop
kill -QUIT 197073 #优雅的退出nginx,等价于 ./nginx -s quit
kill -HUP 197075 #重载配置文件,等价于 ./nginx -s reload
kill -USR1 197220 #重开日志,等价于 ./nginx -s reopen
kill -WINCH 197222 #优雅的关闭worker进程
备注:信号都是发送给nginx的master进程的
先安装一个nginx-1.18.0旧版本来演示
useradd -s /sbin/nologin -M nginx
yum -y install gcc gcc-c++ make pcre pcre-devel zlib-devel zlib openssl-devel openss
wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar zxvf nginx-1.18.0.tar.gz
cd nginx-1.18.0
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_modul
make -j 8
make install
cd usr/local/nginx/sbin
./nginx
ps -ef | grep nginx
root 1679 1 0 11:23 ? 00:00:00 nginx: master process ./nginx
nginx 1680 1679 0 11:23 ? 00:00:00 nginx: worker process
nginx 1681 1679 0 11:23 ? 00:00:00 nginx: worker process
#下面开始平滑升级nginx为nginx-1.22.0版本,不停nginx升级,实现平滑升级nginx
方法一、 nginx平滑升级
1、如果我们想要更换
nginx
版本,升级为更高版本的
nginx
,无非就是重新编译安装新版本的
nginx
,然后停止旧版本
nginx
,启动新版本
nginx
。这切换期间势必存在
nginx
服务不可用。(因为我们不能同时启动两个版本的
nginx
,会存在端口冲突的问题)
2、官网给我们提供了上面问题的解决方案,即平滑升级
nginx
,所谓平滑升级是指旧的
nginx
不停止,新的
nginx
又可以启动,即同时存在旧的
nginx
和新的
nginx
,当旧的
nginx
请求处理完毕,关闭旧的
nginx
。这就要用到我们前面所说的
USR2
信号来实现
nginx
的平滑升级了。
USR2 平滑启动nginx进程
WINCH 优雅的停止worker进程
QUIT 优雅的停止旧的master进程
先查看现在的nginx的版本:
/usr/local/nginx/sbin/nginx -V
ginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module
编译安装高版本的
nginx
,编译参数要与原来旧版本参数的一致(只多不少),安装路径要与原来旧版本安装路径一样;
注意:升级新版本,新版本的安装路径要与旧版本的安装路径保持一致,安装完成,会在
sbin
目录下存在一个
nginx(新版本)、nginx.old(旧版本)
;
wget http://nginx.org/download/nginx-1.22.0.tar.gz
tar -zxvf nginx-1.22.0.tar.gz
cd nginx-1.22.0
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module
make -j 8 && make install
[root@nginx ~]# cd /usr/local/nginx/sbin #进入nginx的目录
[root@nginx sbin]# ll #查看nginx的可执行文件,可以看到我们现在有两个nginx的可执行文件
total 11712
-rwxr-xr-x 1 root root 6034160 Sep 23 12:47 nginx #新版本的nginx-1.22.0
-rwxr-xr-x 1 root root 5952184 Sep 23 11:22 nginx.old #原来旧版本nginx-1.18.0被备份为nginx.old了
[root@nginx sbin]# ./nginx -V #查看nginx的版本,确认是新版本的nginx-1.22.0
nginx version: nginx/1.22.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module
[root@nginx sbin]# ./nginx.old -V #查看nginx的版本,确认是旧版本的nginx-1.18.0
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module
[root@nginx sbin]#
这时候直接
./nginx
启动新版本肯定是报错的,因为端口被占用,我们需要使用
USR2
来平滑升级
nginx
#先查看旧版本的nginx的进程
[root@nginx sbin]# ps -ef | grep nginx
root 1679 1 0 11:23 ? 00:00:00 nginx: master process ./nginx #记住旧版本的nginx的master进程pid
nginx 1851 1679 0 11:25 ? 00:00:00 nginx: worker process
nginx 1852 1679 0 11:25 ? 00:00:00 nginx: worker process
[root@nginx sbin]#
#使用 kill -USR2 旧的主进程号 命令来平滑升级
[root@nginx sbin]# kill -USR2 1679 #向旧版本nginx的master进程发送USR2信号
#再查看nginx的进程,这时就启动新版本的nginx进程,此时同时存在新旧版本的nginx进程
[root@nginx sbin]# ps -ef | grep nginx
root 1679 1 0 11:23 ? 00:00:00 nginx: master process ./nginx #这是旧版本的nginx/1.18.0
nginx 1851 1679 0 11:25 ? 00:00:00 nginx: worker process #这是旧版本的nginx/1.18.0
nginx 1852 1679 0 11:25 ? 00:00:00 nginx: worker process #这是旧版本的nginx/1.18.0
root 9336 1679 0 12:55 ? 00:00:00 nginx: master process ./nginx #这是新版本的nginx/1.22.0
nginx 9337 9336 0 12:55 ? 00:00:00 nginx: worker process #这是新版本的nginx/1.22.0
nginx 9338 9336 0 12:55 ? 00:00:00 nginx: worker process #这是新版本的nginx/1.22.0
#先使用 kill -WINCH 旧的主进程号 命令优雅的关闭旧版本的worker进程(等连接基本处理完毕了在关闭旧的worker进程也不迟)
[root@nginx sbin]# kill -WINCH 1679 #向旧版本nginx的master进程发送WINCH信号,告知其优雅的停止worker进程
#确认新版nginx升级没有问题了,再使用命令 kill -QUIT 旧的主进程号 优雅的关闭旧版本的nginx master进程
[root@nginx sbin]# kill -QUIT 1679 #向旧版本nginx的master进程发送QUIT信号,告知其优雅的退出
#至此,此时已经完成了nginx版本的平滑升级
方法二、 nginx平滑升级
编译安装高版本的nginx:
wget http://nginx.org/download/nginx-1.22.0.tar.gz
tar -zxvf nginx-1.22.0.tar.gz
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module
#预编译完成后会得到一个Makefile 文件,我们来看下这个文件的内容,如下:
[root@nginx nginx-1.22.0]# cat Makefile
default: build
clean:
rm -rf Makefile objs
.PHONY: default clean
build:
$(MAKE) -f objs/Makefile
install:
$(MAKE) -f objs/Makefile install
modules:
$(MAKE) -f objs/Makefile modules
upgrade:
/usr/local/nginx/sbin/nginx -t
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid` #平滑升级
sleep 1
test -f /usr/local/nginx/logs/nginx.pid.oldbin
kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin` #优雅的关闭旧版本的nginx
.PHONY: build install modules upgrade
[root@nginx nginx-1.22.0]#
#如上看到的,make 命令有个参数upgrade,这个参数就是平滑升级的,看内容应该可以看到,其平滑升级的原理仍然是我们前面方法一的说的一样,先
#发送 USR2 信号给旧的nginx master进程告知其平滑升级,拉起新版本的nginx进程,然后再发送QUIT信号给旧版本的master进程,优雅的关闭旧版
#本的nginx。
[root@nginx sbin]# make install && make upgrade #直接平滑升级
[root@nginx sbin]# ll
total 11712
-rwxr-xr-x 1 root root 6034160 Sep 23 17:36 nginx #新版本的nginx
-rwxr-xr-x 1 root root 5952184 Sep 23 17:27 nginx.old #就版本的nginx
[root@nginx sbin]#
[root@nginx sbin]# ps -ef | grep nginx #现在只有新版本的nginx
root 31946 1 0 17:36 ? 00:00:00 nginx: master process ./nginx
nginx 31947 31946 0 17:36 ? 00:00:00 nginx: worker process
root 32137 15942 0 17:40 pts/4 00:00:00 grep --color=auto nginx
[root@nginx sbin]#
#至此,nginx平滑升级完成
方法三、 nginx平滑升级(保守方法)
同理,解压编译新版本的nginx,但此时的安装路径安装在一个全新的目录,不再与原来旧版本的安装路径一样。
wget http://nginx.org/download/nginx-1.22.0.tar.gz
tar -zxvf nginx-1.22.0.tar.gz
./configure --prefix=/usr/local/nginx2 --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module
make -j 8 && make install #安装全新版本的nginx
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old #备份原来的旧版本的nginx,备份不影响正在运行的nginx进程
cp /usr/local/nginx2/sbin/nginx /usr/local/nginx/sbin/ #将新版本的nginx可执行文件复制到旧版本的安装路径下
#同理,下面的步骤仍然是发送信号SER2给旧版本的nginx的master进程进行平滑升级nginx,然后再关闭旧版本的worker进程和master进程
[root@nginx sbin]# kill -USR2 1679 #向旧版本nginx的master进程发送USR2信号,让其拉起新版本的nginx
#先使用 kill -WINCH 旧的主进程号 命令优雅的关闭旧版本的worker进程
[root@nginx sbin]# kill -WINCH 1679 #向旧版本nginx的master进程发送WINCH信号,告知其优雅的停止worker进程
#确认nginx升级没有问题了,再使用命令 kill -QUIT 旧的主进程号 优雅的关闭旧版本的nginx master进程
[root@nginx sbin]# kill -QUIT 1679 #向旧版本nginx的master进程发送QUIT信号,告知其优雅的退出
#至此,已经完成了nginx版本的平滑升级
nginx版本回退
如果在使用新版本的
nginx
过程中发现新版本存在问题,那么可以进行
nginx
版本回退,回退到旧版本的
nginx
。
版本回退可以分2种情况,如下:
1、事前对旧版本
nginx
进行备份,若出现问题,直接将旧版本重新拷贝会
/usr/local
目录下,重启
nginx
旧版本操作,执行如下:
#停止nginx服务进行版本回退
killall nginx
cp /usr/local/nginx-1.18.0.bak /usr/local/nginx
/usr/local/nginx/sbin/nginx
#检查nginx状态
ps -ef |grep nginx
2、在新版本
nginx
的
master
进程和旧版本的master进程同时存在时,即只关闭了旧版本的
worker
进程没有关闭旧版本的
master
进程的情况下,可以这样回滚,如下:
#向旧版本的master进程发送HUP信号,重载配置,会重新拉起新的worker进程
kill -HUP 旧masterPID # HUP是重载配置,会重新启动worker进程
#关闭新版本nginx的master进程,并将原sbin目录下的nginx.old(旧版本nginx二进制文件)重新改回nginx,以便管理nginx
kill -WINCH 新master的PID #优雅额关闭新版本的worker进程
kill -QUIT 新master的PID #优雅额关闭新版本的matser进程
cd /usr/local/nginx/sbin/
mv nginx nginx_1.22.0_bak #先备份新版本的nginx可执行文件
mv nginx.old nginx #将旧版本的nginx可执行文件恢复回来
总结
nginx支持的kill发送以下的信号:
kill -TERM 195916 #强制停止nginx,等价于 ./nginx -s stop
kill -INT 197019 #强制停止nginx,等价于 ./nginx -s stop
kill -QUIT 197073 #优雅的退出nginx,等价于 ./nginx -s quit
kill -HUP 197075 #重载配置文件,等价于 ./nginx -s reload
kill -USR1 197220 #重开日志,等价于 ./nginx -s reopen
kill -USR2 197220 #平滑升级nginx
kill -WINCH 197222 #优雅的关闭worker进程
备注:信号都是发送给nginx的master进程的
平滑升级nginx的大概思路:
方法一、
1、编译安装高版本的nginx,其./configure预编译的参数要与原来旧版本的参数一致,包括安装路径也要一致;
2、make -j 10 && make install 编译安装;
3、安装完成之后,在/usr/local/nginx/sbin/目录下就会存在一个可执行文件,nginx、nginx.old,前者是新版本的可执行文件,后者是旧版本的可执行文件;
4、使用 kill -USR2 旧版本的masterPID 命令进行平滑升级,此时就会同时存在新版本旧版本的nginx进程;
5、使用 kill -WINCH 旧版本的masterPID 命令优雅的关闭旧版本的worker进程
6、确认新版本的nginx进程没有问题后,此时可以使用 kill -QUIT 旧版本的masterPID 命令优雅的关闭旧版本的master进程;
7、nginx升级已完成。
方法二、
1、编译安装高版本的nginx,其./configure预编译的参数要与原来旧版本的参数一致,包括安装路径也要一致;
2、make install && make upgrade 编译安装,make upgrade直接平滑升级;
3、安装完成之后,在/usr/local/nginx/sbin/目录下就会存在一个可执行文件,nginx、nginx.old,前者是新版本的可执行文件,后者是旧版本的可执行文件;
4、此时平滑升级完成了,ps -ef | grep nginx 查看只会有新版本的nginx,因为当你执行make upgrade的时候,其实已经发送了kill -QUIT 信号给旧版本的nginx,所以旧版本的nginx进程已经优雅的退出了。
5、nginx升级已完成。
方法三、(保守方法)
1、解压编译新版本的nginx,但此时的安装路径安装在一个全新的目录,不再与原来旧版本的安装路径一样;
2、备份旧版本的可行性文件,复制新版本的nginx的可执行文件
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old #备份原来的旧版本的nginx,备份不影响正在运行的nginx进程
cp /usr/local/nginx2/sbin/nginx /usr/local/nginx/sbin/ #将新版本的nginx可执行文件复制到旧版本的安装路径下
3、使用 kill -USR2 旧版本的masterPID 命令进行平滑升级,此时就会同时存在新版本旧版本的nginx进程;
4、使用 kill -WINCH 旧版本的masterPID 命令优雅的关闭旧版本的worker进程
5、确认新版本的nginx进程没有问题后,此时可以使用 kill -QUIT 旧版本的masterPID 命令优雅的关闭旧版本的master进程;
6、nginx升级已完成。
版本回退:
1、如果事前对旧版本
nginx
进行备份,若出现问题,直接将旧版本重新拷贝会
/usr/local
目录下,重启
nginx
旧版本操作,执行如下:
#停止nginx服务进行版本回退
killall nginx
cp /usr/local/nginx-1.18.0.bak /usr/local/nginx
/usr/local/nginx/sbin/nginx
#检查nginx状态
ps -ef |grep nginx
2、在新版本nginx的master进程和旧版本的master进程同时存在时,即只关闭了旧版本的worker进程没有关闭旧版本的master进程的情况下,可以这样回滚,如下:
#向旧版本的master进程发送HUP信号,重载配置,会重新拉起新的worker进程
kill -HUP 旧masterPID # HUP是重载配置,会重新启动worker进程
#关闭新版本nginx的master进程,并将原sbin目录下的nginx.old(旧版本nginx二进制文件)重新改回nginx,以便管理nginx
kill -WINCH 新master的PID #优雅额关闭新版本的worker进程
kill -QUIT 新master的PID #优雅的关闭新版本的matser进程
cd /usr/local/nginx/sbin/
mv nginx nginx_1.22.0_bak #先备份新版本的nginx可执行文件
mv nginx.old nginx #将旧版本的nginx可执行文件恢复回来