【每天5分钟,了解一个知识点】
该问题经常在面试Nginx的时候提到,索性就放到Nginx系列里面聊聊
一、问题起源与发
C10K 问题提出:1999 年 Dan Kegel 提出,当时服务器是 32 位系统,如 Linux 2.2 后升级到 2.4 和 2.6(2.6 才支持 x86_64),配置 2GB 内存和千兆网卡,资源上可处理 10000 个请求,但有软件问题,尤其是网络 I/O 模型问题。
发展到 C10M 和 C1000K:2010 年后硬件发展,C10K 延伸为 C10M,如利用 8 核心 CPU、64G 内存和 10gbps 网络保持 1000 万并发连接。C1000K 即单机处理 100 万个请求,如大型社交网站需要维持大量 TCP 连接,早期互联网用户少无高并发问题,Web2.0 时代用户爆发增长,从 C10K 发展到 C1000K 和 C10M 问题。
二、C10K 的挑战与解决方案
问题:早期 Linux 网络处理采用同步阻塞方式,每个请求分配进程或线程,10000 个请求时,进程或线程调度、上下文切换及内存占用成瓶颈。
解决方案:使用网络 I/O 多路复用模型(select poll epoll)。select 和 poll 采用非阻塞 I/O 和水平触发通知,单线程可监控一批套接字,但需轮询文件描述符列表,耗时且 select 有 1024 个文件描述符限制,poll 无限制但处理耗时与描述符数量是 O(N)关系,且都需在用户空间与内核空间来回切换传递文件描述符集合。epoll 在 Linux 2.6 新增,用红黑树管理文件描述符集合,事件驱动,只关注有 I/O 事件的文件描述符,无需轮询。
三、C1000K 的挑战与突破
早期局限:早期实现 C10K 多采用 select poll,每次监听需复制用户 fd 集合到内核并遍历,select 最多处理 1024 个网络 io 事件,poll 无最大事件数限制但处理耗时与文件描述符数量是 O(N)关系。
epoll 的优势:采用 epoll 可实现 C1000K,无需每次复制用户 fd 集合到内核,通过 epoll_ctl 将用到的 IO 加入内核红黑树,有数据的节点以链表方式连接成队列,epoll_wait 只需复制有数据节点,事件驱动机制提高效率。
四、C10M 的创新路径
传统瓶颈:从网络请求到应用程序数据需两次拷贝,从 C1000K 到 C10M 时,传统方式消耗大量时间和资源,协议栈处理负担重。
DPDK 和 XDP 机制:
DPDK:用户态网络标准,跳过内核协议栈,用户态进程轮询处理网络接收,在 PPS 高的场景有优势,省去硬中断、软中断及协议栈处理过程,可针对场景优化处理逻辑,通过多种机制提高网络包处理效率。
XDP:高性能网络数据路径,基于 eBPF 机制实现,在网络包进入内核协议栈前处理,要求 Linux 4.8 以上版本,无缓存队列,常用于专用网络应用。
五、其他优化策略
工作模型优化:
nginx:主进程 + 多个 worker 子进程,主进程执行 bind()和 listen()后创建子进程处理套接字,worker 进程相互独立,节省锁开销,通过进程间通信实现负载均衡。
netty:accept 线程组 + worker 线程组,accept 线程组负责 accept()并放入队列,worker 线程组处理业务逻辑。
性能限制与解决:
客户端连接数量受限原因:系统资源有限、许可证限制、配置错误、系统负载问题。
解决方法:查看和修改 net.nf_conntrack_max 的值;在注册表建 MaxUserPort 双字节值指定最大临时端口个数(修改后貌似需重启计算机生效)。
【关联阅读】




