Apache与Nginx对客户端请求的处理机制对比

模块

  1. 大致为四个模块,核心模块、HTTP模块、邮件模块,以及第三方模块
  2. 核心模块主要包含两类功能的支持,一类是主体功能,包括进程管理,权限管理,错误日志分析,配置解析。另一类是用于响应请求事件必须的功能,包括事件驱动机制,正则表达式。

APache对客户端请求的处理机制

web-server与client是一对多关系,apache完成并行处理的工作方式如下三种:

  1. 多进程方式
    服务器收到一个请求,其主进程生成一个子进程来处理请求,处理完毕,进程结束。
    为了应对大量请求,apache采用预派生进程的机制来对多进程进行改进。预进程机制就是在请求没到达之前就预先生成好,当请求来的时候主进程分配一个进程与客户端进行交互,交互完成之后,该进程也不结束,而被主进程管理起来等待下一个客户请求的到来。
  2. 多线程方式
    服务器主进程派生一个线程和客户端进行交互。服务器生成一个线程的开销远比进程的开销小,多个线程共享主进程管理的资源。
  3. 异步方式
    发送方在发送一个请求之后,不等待接收方响应这个请求,就继续发送下一个请求,在异步机制中,所有来自发送方的请求形成一个队列,接收方处理完之后才通知发送方。
    同步机制:发送方发送一个请求之后,等待接收方响应这个请求,再继续发送下一个请求。

Nginx对客户端请求的处理机制

Nginx服务器能同时处理大量的请求,结合了多进程机制和异步非阻塞机制。

Nginx服务器启动之后,可以产生一个主进程和多个work进程。Nginx服务器的所有进程用于接收客户端请求,类似与apache的多进程机制,预先派出工作进制,等待客户端请求。

每个work进程使用异步非阻塞方式,可以处理多个客户端的请求。当某个IO请求不能立即得到结果的时候就去处理其他的请求,而客户端在此期间也不需要等待,可以去处理其他的请求,当IO调用返回结果的时候就会通知此work进程,该进程得到通知,暂时挂起当前事务去响应客户端要求。

Nginx的事件驱动模型

IO调用结果如何把自己的状态告诉进程,两种方案

  • work进程过一段时间就去检查一下IO的运行状态,完成则响应,未完成则继续工作。
  • IO调用完之后主动通知work进程

selectpollepoll三种事件驱动模型属于上述的第二种方式

  1. select
  • 创建事件的描述符集合,对于一个事件,关注其上面的读事件、写事件和异常事件,创建三类事件的描述符集合,分别用来收集三种类型的描述符。
  • 其次调用底层select()函数,等待事件发生,轮询所有时间描述符中的每一个描述符,检查是否有事件发生,有则处理,无则继续监听
  1. poll
  • poll和select方式相同,创建描述符的集合,等待事件发生,轮询描述符集合,检查有没有事件发生
  • poll与select的区别在于:select需要为读事件、写事件、异常事件分别创建一个描述符集合,轮询三个集合,而poll库只需要创建一个集合,而每个描述符上面对应的结构分别设置为读事件或写事件或异常事件,轮询一个集合,同时检查这三个事件是否发生。
  1. epoll
  • select和poll都是创建一个待处理的事件列表,然后将列表发给内核,返回时,再去轮询这个列表,来判断是否有事件发生,效率低下。比较好的做法是把描述符列表的管理交给内核负责,一旦有某种事件发生,内核把发生事件的描述符通知给进程,避免轮询整个描述符列表。
  • epoll就是上述做法。通过相关调用通知内核创建一个有N个描述符的列表,给这些描述符设置所关注的事件,并把它添加到内核的事件列表中去,在具体编码过程中也可以通过相关调用删除列表中的描述符。
  • 完成设置之后,epoll就开始等待内核通知事件,某一事件发生以后,内核就将发生事件的描述符传给epoll,得知事件列表的epoll库,就可以开始进行事件处理了。
  • epoll的高效在于它支持一个进程打开大数目的事件描述符,上限是系统可以打开的文件的数目,同时,epoll库的IO效率不随描述符的增加而线性下降。

epoll有两种工作模式:
- 水平触发:内核通知进程来读取数据,进程没来读取数据,内核就一次一次通知进程
- 边缘触发:内核只通知一次让进程来读取数据,进程可以在超时时间内随时来读取数据

备注:这里只是简单的进行了比较和对三种驱动模型的简单介绍,后面会更新更详细的介绍,具体到函数调用

勿忘初心,放得始终