logo

Nginx 与 epoll 的协同工作机制

众所周知,epoll 是一种高性能的事件驱动的 I/O 多路复用机制。那么,相较于 select 这种原始的 I/O 多路复用机制,它具备哪些优势呢?简而言之:实现了从被动到主动的转变。

epoll 化被动为主动,以前 Apache 的 select 模型需要两次遍历才能实现的网络数据包和线程的匹配,现在通过事件驱动的方式主动献上指针,性能暴增。这就像云原生时代的 Prometheus 监控:化主动上传为被动查询,大幅提升了单个数据收集节点的性能上限,成功解决了监控领域的高并发性能问题。

在 5000 个 TCP 连接的情况下,每收到一个数据包,Nginx 找到对应线程的速度比 Apache 高了两个数量级,即便是 event 模式下的 Apache,性能依然远低于 Nginx,因为 Nginx 就是专门为“反向代理”设计的,而 Apache 本质是个 Web 应用容器,无法做到纯粹的事件驱动,其性能自然无法与 Nginx 相提并论。

epoll 的技术原理

笔者将从两个方面讲解 epoll 的技术原理,分别是网络数据包的处理流程,和 I/O 多路复用的实现方式。

1. 网络数据包的处理流程

图 4-2 接收到网络数据包以后的处理流程图

图 4-2 是网卡接收到信息后,把信息发送给用户态的进程处理的流程图。这个过程可以分为四步来理解:

  1. 网卡接收到一段数据,通过 DMA 方式写入内存
  2. NIC 向 CPU 发出硬件中断请求,告诉内核有新的数据过来了
  3. Linux 内核响应中断,系统切换为内核态,处理 Interrupt Handler,从 RingBuffer 拿出一个 Packet,然后解析数据,找到这个端口对应的是哪个 PID,然后包装成 socket 发送给那个进程
  4. 系统切换为用户态,用户进程处理内核传递过来的 socket 数据

2. I/O 多路复用的实现方式

图 4-3 I/O 多路复用原理图

如图 4-3 所示。Nginx 在用户态中创建了一个线程池,池内的每个线程都需要负责处理多个 TCP 连接。通常情况下,这些线程处于休眠状态,不会占用 CPU 资源。当某个 TCP 连接接收到数据时,内核中的事件驱动机制会找到对应的休眠线程,主动调用相应的回调函数。

epoll 真的是非阻塞的吗?

直接给出结论:不是。

首先,需要明确的是,在 Linux 系统下并不存在真正的非阻塞 I/O。

其次,客观上来说,网络连接是一个需要客户端和服务端共同确认的过程,并且由于光速的限制,信息的传递必然需要一定的时间。因此,单个网络连接的模型一定是“阻塞”的:即数据没有返回之前,需要进行等待。

其实我们的宇宙中根本不存在真正的非阻塞 I/O,因为我们的宇宙遵循因果律。

那 Windows IOCP 为什么号称是非阻塞的呢?IOCP 是 Windows 系统提供的一个系统级的非阻塞 I/O 运行库,这套 API 对于我们的调用者进程来说确实是非阻塞的,但实际上在内核层面它仍然是通过线程池实现的,只是这个线程池并没有留给我们自己来实现,而是由内核帮我们实现了而已。

因此,无论是在 Linux 下的 epoll,还是在 BSD 里的 Kqueue,或者是在 Windows 下的 IOCP,它们都只是一种“I/O 多路复用”技术。它们只在“连接数为 10000,但同时收发数据的客户端只有 500 个”的场景下才有意义。换句话说,它们解决的是“明明还有 CPU 和内存资源,为什么客户端无法与服务器建立 TCP 连接”的问题。如果同时有 10000 台客户端同时进行数据收发,那么 epoll 和 select 之间并没有太大的性能差异。

C10K 问题

Nginx 是第一个解决了 C10K 问题的 Web Server。

C10K 指的是单机维持一万个 TCP 连接,首次由 Dan Kegel 在 1999 年提出,最初的那个网页依然可以访问:http://www.kegel.com/c10k.html。

这个问题是怎么出现的呢?因为当初设计 Unix 操作系统的时候没有想到计算机软件的规模会发展到如此的大。就像人类已经经历过的千年虫问题,以及从现在开始 15 年后就要经历的 Unix 时间戳耗尽的问题,Unix 的进程 ID(PID)以及单个进程最大打开文件数都被设定为了“有符号的 16 位整数”,即从 -32767 ~ 32767,所以一台机器在当时的理论极限只有 32767。

Nginx 在用户态利用事件驱动机制,让自己的一个线程可以根据需要绑定多个 TCP 连接,通过这种方式大幅增加了单台服务器所能保持的 TCP 连接数,解决了 C10K 问题。

阅读数:2253      字数:1472 最后更新:2023-10-25 15:42:12