C10K 问题指单机如何支撑一万个并发连接。早期服务器采用"每连接一进程/线程"模型(如 Apache prefork),万级并发意味着上万个进程/线程:内存开销巨大(每个线程栈默认 MB 级)、上下文切换开销随并发数线性增长、调度器不堪重负,系统在吞吐和延迟上崩溃。问题本质是并发模型与 OS 资源的矛盾。
应对方案:
- I/O 多路复用:单线程通过 epoll(Linux)/kqueue(BSD、macOS)同时监听上万连接的读就绪事件,只处理活跃连接,把开销从"连接数"降到"活跃数"。相比 select/poll 的 O(n) 轮询和 1024 描述符上限,epoll 是 O(1) 事件通知(实际 O(活跃数))且无数量硬上限。
- 事件驱动 + 非阻塞 I/O:Nginx、Node.js 的架构核心。
- 多进程/多线程 + Reactor:master-worker 模型(如 Nginx)充分利用多核,进程间用共享内存等协调。
- 配套优化:减少每连接内存(用户态连接结构体代替线程栈)、零拷贝(sendfile)、内核参数调优(文件描述符上限、端口范围、TCP 参数)。
更高并发的 C10M 则涉及用户态协议栈(DPDK)、io_uring 等。追问方向:select/poll/epoll 具体差异、惊群问题、epoll 的边缘触发与水平触发。