Nginx 进程结构
Nginx 的进程结构有单进程和多进程,单进程只适用于开发,不适用于生产,多进程更健壮,利于多核。
当我们启动 Nginx 的时候,首先会创建一个 Master 进程,他是一个父进程,会有很多个子进程。CM(Cache Manage)、CL (Cache Loader) 子进程负责缓存相关,有多个 Worker 子进程,负责处理 Http 请求。Master 进程负责监控 Worker 子进程。这些子进程间的通信是通过共享内存实现的。
为什么 Nginx 采用多进程而不是多线程结构呢?主要是为了 Nginx 的高可用、高可靠。每个进程都有自己独立的地址空间,而一个进程中的所有线程共享这个进程的地址空间。多线程结构的话,当某一个第三方模块引发了一个地址空间的段错误时,在地址越界出现时,会导致整个 Nginx 进程全部挂掉。而多进程结构的话就不会有这个问题。
使用信号管理 Nginx 的父子进程
多进程之间通信通常可以使用共享内存、信号等。Nginx 做进程间管理的时候,通常只使用信号。
发送和处理信号地有 Master 进程、Worker 进程、nginx 命令行。
Nginx 中常见的信号有:
- TERM:立刻停止 Nginx 进程
- QUIT:优雅停止 Nginx 进程
- HUP:重载配置文件
Master 进程会监控 Worker 进程有无发送 CHLD 信号,当子进程终止的时候回想父进程发送 CHLD 信号。还会管理 Worker 进程,通过接收 TERM 等信号。
Worker 进程会接收 TERM 等信号,做出相应的处理。
当我们输入 Nginx 命令行时,实际也是在给进程发信号。Nginx 启动后有个 pid 文件,这个 pid 文件记录了 Master 进程的 pid ,当我们用 nginx -s 这样的命令行时,nginx 命令行工具会去 pid 文件读取 Master 进程的 pid ,向这个进程发送命令对应的信号。
优雅地关闭 worker 进程
优雅地关闭,是针对 worker 进程而言的,因为只有 worker 进程 才会处理请求。当我们在处理一个连接的时候,直接去关闭连接会导致用户收到错误,所以优雅地关闭是指 Nginx 的 worker 进程 可以识别出当前连接没有正在处理请求,这个时候再把连接进行关闭。
优雅地关闭 worker 进程主要针对的是 Http 请求而言,对于某些请求, Nginx 无法优雅关闭进程。比如当 Nginx 代理 websocket 协议时,当 Nginx 做 TCP 层或 UDP 层的反向代理时。这些时候 Nginx 无法识别出当前连接有无正在处理请求。
优雅地关闭 worker 进程步骤:
- 设置定时器 workshutdown_timeout
- 关闭监听句柄
- 关闭线程池空闲连接
- 在循环中等待全部连接关闭
- 退出进程
当所有连接被优雅地关闭,或者达到了 workershutdown_time_out 时间定时器以后,worker 进程都会立即退出。