1. WEB请求处理机制

1.1. WEB 服务器常用的处理请求方式

1.1.1. 多进程方式

Apache 的 Prefork 模式就是多进程处理方式,当收到客户端的请求时,由服务器的主进程生成一个子进程来和该客户端进行交互。
该方式的优势是各个进程之间相互隔离,保证的服务器的稳定性。但是缺点很明显,对服务器的资源,尤其是内存的消耗很大,进程之间的上下文切换太重量级了,不适合大并发的场景。

1.1.2. 多线程的方式

Apache 的 worker模式和event模式就是多线程方式,当收到客户端的请求时,由服务器的工作进程生成一个线程来处理。
该方式的优势是大大增强了服务器处理并发请求的能力,但是socket本身是阻塞状态的,当有10万并发连接访问时,就需要10万的线程来维护这些请求,线程的上下文切换非常平台,会引发很严重的性能问题。

1.1.3. 异步方式

  • 同步和异步

同步是指在发送方发出消息后,需要等待接收到接收方发回的响应,或者通过回调函数来接收到对方响应信息。
异步是指在发送方发出请求后,接收方不返回消息或者不等待返回消息。

  • 阻塞和非阻塞

在网络通讯中,阻塞和非阻塞主要是指Socket的阻塞和非阻塞方式,而socket的实质是IO操作。
阻塞是指在IO操作返回结果之前,当前的线程处于被挂起状态,直到调用结果返回后才能处理其它新的请求。
非阻塞指在IO操作返回结果之前,当前的线程会继续处理其它的请求。

  • 同步阻塞方式(常用,简单)

发送方向接收方发送请求后,一直处理等待响应状态。接收方处理请求时进行IO操作,如果该操作没有立刻返回结果,将继续等待,直到返回结果后,才响应发送方,期间不能处理其它请求。

  • 异步非阻塞(常用)

发送方向接收方发送请求后,继续进行其它工作。接收方处理请求进行IO操作,如果没有立刻返回结果,将不再等待,而是处理其它请求。

1.2. Nginx服务器处理请求的方式

1.2.1. Nginx的异步非阻塞

Nginx 在服务启动后会产生一个主进程(master process)、多个工作进程(worker processes)、缓存加载进程(cache load processes)、缓存管理进程(cache manager processes),工作进程用于接收和处理客户端请求。
每个工作进程使用了异步非阻塞的方式,可以处理多个客户端的请求。当某个工作进程接收到客户端的请求后,使用事件驱动方式管理socket,将socket设置为非阻塞方式。
在涉及IO操作时,可以调用Linux文件系统提供的AIO接口,使用异步IO方式完成调用,针对任务繁重的IO操作可以将等待IO的操作卸载给线程池中其它线程处理,从而避免主线程(worker进程的主循环)阻塞。

1.2.2. Nginx处理请求的过程

02-Nginx事件模型 - 图1
02-Nginx事件模型 - 图2

2. 事件驱动模型

Nginx管理socket的方式称为事件驱动模型。

2.1. SELECT 库

各个版本的Linux和Windows平台都支持的基本事件驱动模型,并在接口定义上基本相同,使用步骤如下

  • 创建所关注事件的描述符集合,对于一个描述符,可以关注其上面的读(read),写(write),异常(Exception)事件,所以要创建三类文件描述符集合。
  • 调用底层提供的select()函数,等待事件发生。
  • 轮询所有事件描述符集合中的每一个事件描述符,检查是否有相应的事件发生。

Nginx在安装时未指定其它高性能事件驱动模型库,会自动编译安装该库。

2.2. POLL 库

Poll库是Linux平台的事件驱动模型,在Linux 2.1.23中引入。
Poll库与Select类似,区别是select会创建三类事件描述符,而poll只创建一类描述符集合,所以缩减了轮询的时间。
Nginx在安装时未指定其它高性能事件驱动模型库,会自动编译安装该库。

2.3. EPOLL库

无论是SELECT还是POLL事件驱动模型,都是需要使用轮询的方法检查连接是否有新的事件,在连接数非常多的时候,轮询会非常消耗性能。
Epoll库是Linux高性能事件驱动模型库,其效率远超poll和select库。Linux 2.6及以上的版本都可以使用。

  • 首先,当有新的socket连接时,nginx使用epoll库创建与socket相关联的文件描述符,并设置需要关注的事件,并将其添加到内核事件列表中。
  • 然后,epoll库等待内核通知即可。省掉了select和poll库中轮询文件描述符的步骤。

Epoll库支持一个进程打开最大数目的事件描述符,上限是系统可以打开文件的最大数目;同时epoll库的IO效率不随文件描述符的增加而线性下降,因为它只会对内核上报的”活跃的描述符进行操作。


3. Nginx的进程

3.1 进程的分类

3.1.1. master process

Nginx启动时运行的主要进程,主要功能如下

  • 读取Nginx配置文件
  • 建立、绑定、关闭socket.
  • 按照配置生成、管理进程.
  • 接收外界指令,如重启、退出等
  • 编译和处理Perl脚本
  • 开启日志记录

    3.1.2. worker processes

  • 接收并处理客户端请求

  • 访问和调用缓存数据
  • 接收主程序的指令

    3.1.3. cache loader

    在开启缓存服务器功能下,在Nginx主进程启动一段时间后(默认1分钟),由主进程生成cache loader,在缓存索引建立完成后将自动退出。

    3.1.4. Cache Manager

    在开启缓存服务器功能下,在Nginx主进程的整个生命周期内,管理缓存索引,主要对索引是否过期进程判断。

    3.2. 进程之间的交互

    3.2.1. 主进程与工作进程的交互

    主进程生成工作进程的时候,会将工作进程添加到工作进程列表中,并建立一个主进程到工作进程的单向管道。当主进程需要与工作进程进行交互时,主进程通过管道向工作进程发出指令,工作进程读取管道中的数据。

    3.2.2. 工作进程与工作进程的交互

    主进程在生成工作进程时,会将工作进程添加到工作进程列表中,并将该进程的ID等信息通过管道传递给其他进程。
    当工作进程需要与其他工作进程通讯时,会从主进程给予的工作进程信息中找到对方进程的ID,然后建立与对方进程的管道,进行信息传递。