Skip to content

Nginx 架构

1. Nginx 进程模型

Nginx 默认采用多进程工作方式,在 Nginx 启动后,会运行一个 master 进程和多个 worker 进程。

master 主要用来管理 worker 进程,充当整个进程组与用户的交互接口,同时对进程进行监护,实现 worker 进程的重启服务、平滑升级、更换日志文件、配置文件实时生效等功能;

worker 进程用来处理基本的网络事件,worker 之间是平等的,他们共同竞争来处理来自客户端的请求。一个请求只能在一个 worker 进程中处理,一个 worker 进程不可能处理其它 worker 进程中的请求。

另外在 Nginx 架构中还有 Cache Loader 和 Cache Manager 进程,Cache Loader 进程加载缓存索引文件信息;Cache Manager 进程管理磁盘的缓存大小,超过预定值大小后最小使用的数据将被删除。

1.1 Master 管理进程

Master 进程主要用来管理 worker 进程,具体包括如下 4 个主要功能:

  • 接收来自外界的信号;

  • 向各 worker 进程发送信号;

  • 监控 worker 进程的运行状态;

  • 当 worker 进程退出后(异常情况下),会自动重新启动新的 worker 进程。

Master 进程接受到命令重启 Nginx 进程(./nginx -s reload),会按照以下流程:

首先 master 进程在收到重启命令后,会先重新加载配置文件,然后再启动新的 worker 进程,并向所有老的 worker 进程发送信号,告诉他们可以光荣退休了。

新的 worker 进程在启动后,就开始接收新的请求,而老的 worker 在收到来自 master 的信号后,就不再接收新的请求,并且处理完当前进程中的所有未处理完的请求后,再退出。

1.2 Worker 工作进程

Worker 工作进程之间是对等的,每个进程处理请求的机会也是一样的。Nginx 采用异步非阻塞的方式来处理网络事件,具体流程如下:

  1. 接收请求:首先,每个 worker 进程都是从 master 进程 fork 过来,在 master 进程建立好需要 listen 的 socket(listenfd)之后,然后再 fork 出多个 worker 进程。

    • 所有 worker 进程的 listenfd 会在新连接到来时变得可读,每个 work 进程都可以去 accept 这个 socket(listenfd)。

    • 当一个 client 连接到来时,所有 accept 的 work 进程都会受到通知,但只有一个进程可以 accept 成功,其它的则会 accept 失败。

    • 为保证只有一个进程处理该连接,Nginx 提供了一把共享锁 accept_mutex 来保证同一时刻只有一个 work 进程在 accept 连接。

    • 所有 worker 进程在注册 listenfd 读事件前抢 accept_mutex,抢到互斥锁的那个进程注册 listenfd 读事件,在读事件里调用 accept 接受该连接。

  2. 处理请求:当一个 worker 进程在 accept 这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接。

由上可以看出,一个请求完全由 worker 进程处理,并且只在一个 worker 进程中处理。

2. Nginx 请求处理流程

Nginx 工作进程会监听套接字上的事件(accept_mutex和kernel socketsharding),来决定什么时候开始工作。事件是由新的连接初始化的,这些连接会被分配给状态机,Nginx 中有三大类状态机:处理应用层的 HTTP 状态机、处理 TCP/UDP 的 4 层的传输层状态机和处理邮件的 MAIL 状态机,其中 HTTP 状态机最为常见。

在多种流量进入 Nginx 后,Nginx 的三种状态机在 Nginx 解析出请求后,会动用线程池处理调用,将静态资源、反向代理、错误日志等信息分别导向不同的出口,比如 fastcgi 会导向 PHP 处理、html 会导向 nginx 处理,并将处理请求日志记录到本地或远程服务器中。

3. Nginx 多进程 IO 模型

3.1 Nginx 多进程模型

Nginx 默认使用多进程的工作方式,相比较多线程的方式,有以下好处:

  1. 首先,对于每个 worker 进程来说,独立的进程不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多;

  2. 其次,采用独立的进程,可以让进程之间相互不会影响,一个进程退出后,其它进程还在工作,服务也不会中断,master 进程则很快启动新的 worker 进程;

  3. 再次,为 Nginx 热部署提供了支持。在修改配置文件 nginx.conf 后,重新生成新的 worker 进程,新的 worker 进程会以新的配置处理请求,而老的 worker 进程,等把以前的请求处理完成以后,kill 掉就可以。

3.2 Nginx 异步非阻塞事件模型

异步非阻塞事件是怎么回事?先看一个请求的完整过程,首先请求过来建立连接,然后再接收数据再发送数据,具体到系统层就是 IO 读写事件。当读写事件没有准备好,如果不采用非阻塞的方式,就得阻塞调用,阻塞调用会进入内核等待,导致 CPU 资源被其它进程占用。当并发请求越大时,等待的事件越多,CPU 利用不上去,并发也上不去。因此 Nginx 使用非阻塞的事件模型,系统中事件模型有很多中,比如 select/poll/kqueue/epoll 等,Nginx 采用 epoll 模型。Epoll 模型基于事件驱动机制,可以监控多个事件是否准备完毕,如果可以,就放入 epoll 队列,这个过程是异步的,worker 进程只需要从 epoll 队列循环处理即可。Epoll 调用过程如下图所示: