nginx不停机优雅升级

Nginx可通过信号量进行优雅升级,以达成高可用的目标。

Nginx信号量

可使用如下信号对nginx主进程进行管理:

TERM, INT  快速关机,快速关闭主进程及工作进程。
QUIT       优雅的关机,正常关闭主进程和工作进程。
HUP        使用新配置启动新的工作进程,正常关闭旧工作进程。告诉Nginx主进程重新读取其配置文件,并将工作进程替换为新配置的工作进程。如果新旧主机正在运行,则将其发送到旧主机,将使用原始配置生成工作程序。          
USR1       重新打开日志文件
USR2       升级可执行文件,这会产生一组新的主/工作流程,而不会影响旧的流程。
WINCH      优雅地关闭工作进程,告诉Nginx主进程正常停止其关联的工作程序实例。
KILL       会立即杀死主进程及工作进程,无需做任何清理。

可使用如下信号对nginx工作进程进行管理:

TERM, INT    快速退出进程
QUIT         优雅退出进程
USR1         重新打开日志文件
WINCH        调试异常终止(需要启用debug_points)

修改配置

Nginx默认将主进程ID写入/usr/local/nginx/logs/nginx.pid文件,可在nginx.conf中使用pid指令更改路径和名称 。

为了让nginx重新读取配置文件,需将HUP信号发送给主进程。

主进程首先检查语法有效性,然后,尝试使用新配置,即打开日志文件和新socket监听。

若操作失败,则回滚修改继续使用旧配置。

若成功,将启动新的工作进程,并向旧工作进程发出消息,要求它们正常退出。

旧工作进程关闭socket监听,但会继续为已经连接的客户端提供服务。在为所有已连接的客户端服务完后,旧工作进程将退出。

查看Nginx PID

ps aux | grep nginx

查找nginx主进程ID的另一种方法是打印/run/nginx.pid:

cat /run/nginx.pid

替换

sudo kill -s USR2 10846

关闭主进程

sudo kill -s WINCH `cat /run/nginx.pid.oldbin`
sudo kill -s QUIT `cat /run/nginx.pid.oldbin`

示例

假如在linux上为nginx运行如下命令:

ps axw -o pid,ppid,user,%cpu,vsz,wchan,command | egrep'(nginx | PID)'

输出如下:

PID PPID USER%CPU VSZ WCHAN COMMAND 
33126 1 root 0.0 1148 pause nginx:master process /usr/local/nginx/sbin/nginx 
33127 33126 nobody 0.0 1380 kqread nginx:worker process(nginx)
33128 33126 nobody 0.0 1364 kqread nginx:worker process(nginx)
33129 33126 nobody 0.0 1364 kqread nginx:worker process(nginx)

将HUP发送到主进程

kill HUB 33126

则输出如下:

PID PPID USER%CPU VSZ WCHAN COMMAND
33126 1 root 0.0 1164 pause nginx:master process /usr/local/nginx/sbin/nginx 
33129 33126 nobody 0.0 1380 kqread nginx:工作进程正在关闭 (nginx)
33134 33126 nobody 0.0 1368 kqread nginx:worker process(nginx)
33135 33126 nobody 0.0 1368 kqread nginx:worker process(nginx)
33136 33126 nobody 0.0 1368 kqread nginx:worker process(nginx)

PID为33129的旧工作进程仍在工作:

PID PPID USER%CPU VSZ WCHAN COMMAND 
33126 1 root 0.0 1164 pause nginx:master process /usr/local/nginx/sbin/nginx 
33134 33126 nobody 0.0 1368 kqread nginx:worker process (nginx)
33135 33126 nobody 0.0 1368 kqread nginx:worker process (nginx)
33136 33126 nobody 0.0 1368 kqread nginx:worker process (nginx)

实时升级

使用新版本的可执行文件代替旧版本的文件(nginx)。之后,将USR2信号发送到主进程。主进程首先使用进程ID,将进程文件重命名为带有.oldbin后缀的新文件,如 /usr/local/nginx/logs/nginx.pid.oldbin,然后启动一个新的可执行文件(nginx 服务),该文件再启动新的工作进程:

PID PPID USER%CPU VSZ WCHAN COMMAND 
33126 1 root 0.0 1164 pause nginx:master process /usr/local/nginx/sbin/nginx 
33134 33126 nobody 0.0 1368 kqread nginx:worker process (nginx)
33135 33126 nobody 0.0 1380 kqread nginx:worker process (nginx)
33136 33126 nobody 0.0 1368 kqread nginx:worker process (nginx)
36264 33126 root 0.0 1148 pause nginx:master process /usr/local/nginx/sbin/nginx 
36265 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)
36266 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)
36267 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)

之后,所有的工作进程(新旧进程)继续接受请求。如果将WINCH信号发送到第一个主进程,它将向工作进程发送消息,请求它们正常关闭,工作进程将开始退出:

PID  PPID USER    %CPU   VSZ WCHAN  COMMAND
33126     1 root     0.0  1164 pause  nginx: master process /usr/local/nginx/sbin/nginx
33135 33126 nobody   0.0  1380 kqread nginx: worker process is shutting down (nginx)
36264 33126 root     0.0  1148 pause  nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
36266 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)
36267 36264 nobody   0.0  1364 kqread nginx: worker process (nginx)

一段时间后,只有新的工作进程在处理请求:

PID PPID USER%CPU VSZ WCHAN COMMAND 
33126 1 root 0.0 1164 pause nginx:master process /usr/local/nginx/sbin/nginx 
36264 33126 root 0.0 1148 pause nginx:master process /usr/local/nginx/sbin/nginx 
36265 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)
36266 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)
36267 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)

Nginx主进程

Nignx更新升级需注意,旧的主进程不会关闭其侦听的sockets,所以能在需要时,通过管理信号再次启动它所属的工作进程。

如,由于某种原因新的可执行文件无法达到预期,或升级无法接受(想找回旧版nginx服务),可以利用这一点将nginx工作进程恢复到旧版本。

Nginx回退版本

如果对nginx升级结果不满意,可通过如下操作,回退到旧版本。

首先,将HUP信号发送给旧版本的主进程,旧版本的主进程将启动新的工作进程,此时,无需重新读取配置。

然后,将QUIT信号发送到新版本的主进程,使其进入正常关闭流程。

最后,将TERM信号发送到新版本的主进程,它会向其工作进程发送一条消息,要求它们立即退出,这些工作进程一般会立即退出。

如果,由于某种原因新进程没有退出,则通过发送KILL信号强制它们退出。

当新版本的主进程退出时,旧版本的主进程将自动创建新进程进行处理。如果新版本的主进程成功退出,则旧版本的主进程会将旧pid文件中.oldbin后缀去掉。

如果升级成功,应将QUIT信号发送到旧版本的主进程,只保留新版本进程:

PID PPID USER%CPU VSZ WCHAN COMMAND 
36264 1 root 0.0 1148 pause nginx:master process /usr/local/nginx/sbin/nginx 
36265 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)
36266 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)
36267 36264 nobody 0.0 1364 kqread nginx:worker process (nginx)