通过信号控制 nginx

nginx 可以通过信号进行控制。master 进程的进程 ID 默认写入文件 /usr/local/nginx/logs/nginx.pid(Windows 系统进程 ID 位于 %nginx_home%/logs/nginx.pid)。保存进程 ID 的文件名称可以在配置时更改,或者在 nginx.conf 中使用 pid 指令更改。

主进程支持以下信号:

  • TERM, INT:快速关闭

  • QUIT:优雅的关闭

  • HUP:更改配置,跟上变化的时区(仅适用于 FreeBSD 和 Linux),使用新配置启动新工作进程,正常关闭旧工作进程

  • USR1:重新打开日志文件

  • USR2:升级可执行文件

  • WINCH:优雅的关闭工作进程

单个工作进程(worker processes)也可以用信号控制,尽管这不是必需的。支持的信号有:

  • TERM, INT:快速关闭

  • QUIT:优雅的关闭

  • USR1:重新打开日志文件

  • WINCH:终止调试异常(需要启用 debug_points)

更改 nginx 配置

为了让 nginx 重新读取配置文件,应该向主进程发送一个 HUP 信号。 主进程首先检查语法有效性,然后尝试应用新的配置,即打开日志文件和新的监听套接字。如果失败,它会回滚更改并继续使用旧配置。如果成功,它会启动新的工作进程,并向旧的工作进程发送消息,要求它们正常关闭。旧工作进程关闭侦听套接字并继续为旧客户端提供服务。在为所有客户端提供服务后,旧的工作进程将关闭。

让我们通过例子来说明这一点。想象一下 nginx 在 FreeBSD 上运行,如下命令:

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 -HUP 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: worker process is shutting down (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 在 logs 目录下面存在 access.log 和 error.log 两个日志文件。当 nginx 运行一段时间后,日志文件将特别大,不利于我们进行分析。因此,需要按日期或者按照大小对日志文件进行分割,例如:一天一个日志文件。

在 nginx 中为了实现日志文件轮询,需要先将日志文件重命名。如下:

[root@localhost logs]# ll
total 12
-rw-r--r--. 1 root root 1158 Oct  1 07:16 access.log
-rw-r--r--. 1 root root  960 Oct  1 07:10 error.log
-rw-r--r--. 1 root root    6 Oct  1 07:10 nginx.pid
[root@localhost logs]# 
[root@localhost logs]# mv access.log access_bak.log 
[root@localhost logs]# ll
total 12
-rw-r--r--. 1 root root 1158 Oct  1 07:16 access_bak.log
-rw-r--r--. 1 root root  960 Oct  1 07:10 error.log
-rw-r--r--. 1 root root    6 Oct  1 07:10 nginx.pid

然后,将 USR1(重新打开日志文件)信号发送到主进程。主进程将重新打开所有当前打开的日志文件(由于 access.log 已经被重命名为 access_bak.log,因此创建新的 access.log 文件),并为它们分配一个运行工作进程的非特权用户,作为日志文件所有者。命令如下:

# 查看 nginx 进程信息
[root@localhost logs]# ps axw -o pid,ppid,user,%cpu,vsz,wchan,command | egrep '(nginx|PID)'
   PID   PPID USER     %CPU    VSZ WCHAN  COMMAND
 11604      1 root      0.0  20712 sigsus nginx: master process ./sbin/nginx
 11684  11604 nobody    0.0  23220 ep_pol nginx: worker process
 11987  11881 root      0.0 112812 pipe_w grep -E --color=auto (nginx|PID)
# 发送 USR1 信号给 nginx 主进程
[root@localhost logs]# kill -USR1 11604
# 查看 nginx 日志文件
[root@localhost logs]# ll
total 16
-rw-r--r--. 1 root   root 1158 Oct  1 07:16 access_bak.log
-rw-r--r--. 1 nobody root  564 Oct  1 07:18 access.log
-rw-r--r--. 1 nobody root  960 Oct  1 07:10 error.log
-rw-r--r--. 1 root   root    6 Oct  1 07:10 nginx.pid

成功重新打开日志文件后,主进程关闭所有打开的文件(这里指重命名的日志文件),并向工作进程发送消息,要求他们重新打开文件(新的日志文件),工作进程还会立即打开新文件并关闭旧文件。 因此,旧文件几乎可以立即用于后期处理,例如压缩。

动态升级可执行文件

为了升级服务器可执行文件,应首先将新的可执行文件放在旧文件的位置。之后,应将 USR2(kill -USR2 PID) 信号发送到主进程。主进程首先将其带有进程 ID 的文件重命名为带有 .oldbin 后缀的新文件,例如 /usr/local/nginx/logs/nginx.pid.oldbin,然后启动一个新的可执行文件,然后启动新的工作进程:

  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(kill -WINCH PID)信号发送到第一个主进程(PID 为 33126),它将向其工作进程发送消息,请求它们正常关闭,然后它们将开始退出:

  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)

需要注意的是,旧的主进程并没有关闭它的监听套接字,如果需要,它可以被管理再次启动它的工作进程。如果由于某种原因新的可执行文件无法正常工作,可以执行以下操作之一:

  • 将 HUP 信号发送到旧的主进程。旧的主进程将启动新的工作进程而无需重新读取配置。之后,通过向新的主进程发送 QUIT 信号,可以正常关闭所有新进程。

  • 将 TERM 信号发送到新的主进程。然后它会向其工作进程发送一条消息,要求它们立即退出,并且它们几乎都会立即退出。(如果新进程由于某种原因没有退出,应该向它们发送 KILL 信号以强制它们退出)当新的 master 进程退出时,旧的 master 进程将自动启动新的工作进程。

如果新的主进程退出,则旧的s主进程会丢弃带有进程 ID 的文件名中的 .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)
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号