C10K 就是单机同时处理 1 万个请 求(并发连接 1 万)的问题,而 C1000K 也就是单机支持处理 100 万个请求(并发连接 100 万)的问题。

I/O 模型优化

两种I/O事件通知的方式:水平触发和边缘触发

  • 水平触发:只要文件描述符可以非阻塞地执行I/O,就会触发通知。也就是说,应用程序可以随时检查描述符的状态,然后再根据状态,进行I/O操作
  • 边缘触发:只有在文件描述符的状态发生改变(也就是 I/O 请求达到)时,才发送一次通知。

I/O多路复用的方法

  • 第一种,使用非阻塞I/O和水平触发通知,比如使用select或者poll
    • select使用固定长度的位向量,表示文件描述符集合,因此会有最大描述符数量的限制;O(n^2)
    • poll改进select的表示方法,换成一个没有固定长度的数组,这样就没最大描述符数量的限制;O(n)
  • 第二种,使用非阻塞I/O和边缘触发通知,比如epoll
    • epoll使用红黑树,在内核中管理文件描述符的集合。这样就不需要应用程序在每次操作时传入、传出集合
    • epoll使用时间驱动机制,只关注I/O事件发生的文件描述符,不需要轮询扫描整个集合
  • 第三种,使用异步I/O(AIO):异步 I/O 允许应用程序同时发起很多 I/O 操作,而不用等待这些操作完成

工作模型优化

  • 第一种,主进程+多个worker子进程
    • 主进程执行bind()+listen()后,创建多个子进程
    • 然后,每个子进程都通过accept()和epoll_wait(),来处理相同的套接字
  • 第二种,监听相同端口的多进程模型

解决

1.C10K

问题根源:

  1. 一方面 在于系统资源有限
  2. 另一方面 同步阻塞的I/O模型以及轮询的套接字接口,限制了网络事件处理的效率

解决: Linux2.6 引入的epoll

2.C100K

解决:可能只需要增加系统的物理资源就可以满足

3.C1000K

解决:

  1. 不仅仅是增加物理资源就能解决的问题了
  2. 就需要多方面的优化工作 了,从硬件的中断处理和网络功能卸载、到网络协议栈的文件描述符数量、连接状态跟 踪、缓存队列等内核的优化,再到应用程序的工作模型优化,都是考虑的重点。

4.C10M

  1. 就不只是增加物理资源,或者优化内核和应用程序可以解决的问题了。
  2. 这时候,就需要用 XDP 的方式,在内核协议栈之前处理网络包;
  3. 或者用 DPDK 直接跳过网络协议栈,在用户空间通过轮询的方式直接处理网络包。