浅谈Nginx服务器的内部核心架构设计( 二 )


Nginx 是一个 高性能 的 Web 服务器 , 能够同时处理 大量的并发请求  。它结合 多进程机制和 异步机制  , 异步机制使用的是 异步非阻塞方式  , 接下来就给大家介绍一下 Nginx 的 多线程机制 和 异步非阻塞机制  。
3.1. 多进程机制
服务器每当收到一个客户端时 , 就有 服务器主进程 ( master process )生成一个 子进程( worker process )出来和客户端建立连接进行交互 , 直到连接断开 , 该子进程就结束了 。
使用 进程 的好处是 各个进程之间相互独立  ,  不需要加锁  , 减少了使用锁对性能造成影响 , 同时降低编程的复杂度 , 降低开发成本 。其次 , 采用独立的进程 , 可以让 进程互相之间不会影响  , 如果一个进程发生异常退出时 , 其它进程正常工作 ,  master 进程则很快启动新的 worker 进程 , 确保服务不会中断 , 从而将风险降到最低 。
缺点是操作系统生成一个 子进程 需要进行 内存复制 等操作 , 在 资源 和 时间 上会产生一定的开销 。当有 大量请求 时 , 会导致 系统性能下降  。
3.2. 异步非阻塞机制
每个 工作进程 使用 异步非阻塞方式  , 可以处理 多个客户端请求  。
当某个 工作进程 接收到客户端的请求以后 , 调用 IO 进行处理 , 如果不能立即得到结果 , 就去 处理其他请求 (即为 非阻塞 );而 客户端 在此期间也 无需等待响应  , 可以去处理其他事情(即为 异步 ) 。
当 IO 返回时 , 就会通知此 工作进程 ;该进程得到通知 , 暂时 挂起 当前处理的事务去 响应客户端请求  。
4. Nginx事件驱动模型
【浅谈Nginx服务器的内部核心架构设计】在 Nginx 的 异步非阻塞机制 中 ,  工作进程 在调用 IO 后 , 就去处理其他的请求 , 当 IO 调用返回后 , 会 通知 该 工作进程  。对于这样的系统调用 , 主要使用 Nginx 服务器的 事件驱动模型 来实现 。

浅谈Nginx服务器的内部核心架构设计

文章插图
 
如上图所示 ,  Nginx 的 事件驱动模型 由 事件收集器 、 事件发送器 和 事件处理器 三部分基本单元组成 。
  • 事件收集器:负责收集 worker 进程的各种 IO 请求;
  • 事件发送器:负责将 IO 事件发送到 事件处理器 ;
  • 事件处理器:负责各种事件的 响应工作  。
事件发送器将每个请求放入一个 待处理事件列表  , 使用非阻塞 I/O 方式调用 事件处理器 来处理该请求 。其处理方式称为 “多路 IO 复用方法”  , 常见的包括以下三种: select 模型、 poll模型、 epoll 模型 。
5. Nginx进程处理模型
Nginx 服务器使用 master/worker 多进程模式  。多线程启动和执行的流程如下:
  1. 主程序 Master process 启动后 , 通过一个 for 循环来 接收 和 处理外部信号 ;
  2. 主进程通过 fork() 函数产生 worker 子进程  , 每个 子进程 执行一个 for 循环来实现 Nginx 服务器 对事件的接收 和 处理  。
一般推荐 worker 进程数 与 CPU 内核数 一致 , 这样一来不存在 大量的子进程 生成和管理任务 , 避免了进程之间 竞争 CPU 资源 和 进程切换 的开销 。而且 Nginx 为了更好的利用 多核特性  , 提供了 CPU 亲缘性 的绑定选项 , 我们可以将某 一个进程绑定在某一个核 上 , 这样就不会因为 进程的切换 带来 Cache 的失效 。
对于每个请求 , 有且只有一个 工作进程 对其处理 。首先 , 每个 worker 进程都是从 master进程 fork 过来 。在 master 进程里面 , 先建立好需要 listen 的 socket(listenfd) 之后 , 然后再 fork 出多个 worker 进程 。


推荐阅读