nginx 启动时会启动一个主进程,和一个或多个工作进程,前者主要是读取并检查配置文件的合法性;后者则处理实际的请求。
控制 nginx 有两种方式,一种是用 kill 发送信号到 nginx 的主进程(即 nginx.pid 中保存的进程号);另一种则是使用 nginx -s signal;
1. 方式一:kill -s signal PID
主进程和工作进程都可以接收 kill 发送的信号,区别是主进程能处理的信号多一些。
主进程:
-
TERM, INT fast shutdown
-
QUIT graceful shutdown
-
HUP changing configuration, keeping up with a changed time zone (only for FreeBSD and Linux), starting new worker processes with a new configuration, graceful shutdown of old worker processes
-
USR1 re-opening log files
-
USR2 upgrading an executable file
下图是 master 收到 USR2 信号后的状态:
-
WINCH graceful shutdown of worker processes
下图是 master 收到 WINCH 信号后的状态:
工作进程:
- TERM, INT fast shutdown
- QUIT graceful shutdown
- USR1 re-opening log files
- WINCH abnormal termination for debugging (requires debug_points to be enabled)
2. 方式二:nginx -s signal
nginx -s signal
这里的 signal 包括:
- stop — fast shutdown,快速关闭 nginx,不等待工作进程完成当前请求
- quit — graceful shutdown,优雅关闭 nginx,等待工作进程完成当前请求,必须由启动 nginx 的同一个用户来执行,比如 root。普通用户启动的 nginx,root 可以执行 nginx -s quit 来关闭
- reload — reloading the configuration file,重新加载配置文件,使更改的配置生效(以新的配置文件去启动新的工作进程,同时通知旧的工作进程优雅关闭);
下图是收到 reload 信号后的状态:
- reopen — reopening the log files,主要是用于创建新的日志文件,成功后可以对旧的日志文件进行压缩,需要测试:如何保证前后的日志文件名不一样,是通过修改配置文件中的日志文件名还是?如果是那是不是会执行重载配置的动作
3. 问题梳理
3.1 reopen
reopen 执行步骤:
mv /path/to/nginx.log /path/to/backup/nginx.log
kill -USR1 $(cat /path/to/nginx.pid)
由于 linux 内核是根据 inode 来寻找对应的文件,因此重命名并不会影响程序继续向日志文件写入内容;当执行 kill -USR1 后,主进程会打开一个新的配置文件中配置的日志文件(即 /path/to/nginx.log)
- 重命名为什么不会影响进程写入?
文件与 inode 一一对应,但一个文件可以有多个文件描述符对应,文件名是 inode 的别称;
进程通过文件描述符寻找相应的 inode,因此在进程 A 运行过程中,进程 B 修改了文件名,A 仍然可以根究描述符找到对应的 inode 进行写入,因此进程 B 修改了文件名不影响 A 继续向文件写入内容。
3.2 如何升级 nginx 可执行文件
升级前可以先进程简单的测试,看新的二进制程序是否能成功加载配置文件:
nginx -t -c /path/to/nginx.conf
nginx 二进制文件升级步骤如下:
1. 拷贝新的二进制文件以覆盖旧的二进制文件 # 注意备份好旧的二进制文件,以免新的二进制文件执行失败
2. 使用 kill 命令向旧的主进程发送 USR2 信号 # 成功的标志是,有两个主进程以及新的工作进程并存
3. 使用 kill 命令向旧的主进程发送 WINCH 信号 # 此时旧的工作进程会逐步的退出
4. 使用 kill 命令向旧的主进程发送 QUIT 信号
上述是没有意外发生的正常步骤,即新的二进制文件执行正常,那万一新的二进制文件执行出现了错误需要恢复,那么按照下面的恢复步骤操作即可:
使用 kill 命令向旧的主进程发送 HUP 信号 # 此时相当于 nginx -s reload
使用 kill 命令向新的主进程发送 QUIT 信号
上面是在旧的主进程未退出的时候,新的进程出错时的回滚步骤,假如新的进程出错时旧的主进程已经退出了,那么就需要用旧的二进制文件(假设我们做了备份)替换新的二进制文件,此时再做一次 nginx 可执行文件的升级即可。
注意点:保证新、旧二进制文件的安装目录是同一个,因为 nginx 的工作目录以其安装目录为根目录