nginx高效源于将epoll嵌入轻量可控的事件驱动流水线:每个worker独占epoll实例、et模式+非阻塞i/o、空闲连接零开销、内存池与系统参数协同调优。

Nginx 并不是靠“用了 epoll”就自动高效,而是把 epoll 当作一个关键齿轮,嵌进一整套轻量、可控、低开销的事件驱动流水线里。它真正厉害的地方,在于怎么用好这个齿轮,而不是只把它装上去。
每个 worker 绑定一个 epoll 实例,不抢不等
Nginx 启动后,每个 worker 进程都会调用 epoll_create 创建专属的 epoll 实例(epfd),再通过 epoll_ctl 把监听 socket 和后续 accept 到的 client socket 全部注册进去。这样每个 worker 只管自己的 epoll 实例,没有跨进程共享 fd 的锁竞争,也不用轮询或等待其他 worker —— 事件来了,就处理;没来,就继续空转,不浪费 CPU。
用 ET 模式 + 非阻塞 I/O,一次唤醒干完活
Nginx 默认启用 epoll 的边缘触发(ET)模式,并强制所有 socket 设为 non-blocking。这意味着:当一个连接有数据可读时,epoll_wait 只通知一次;Nginx 必须循环调用 recv(),直到返回 EAGAIN,才算真正读完。这种“一次唤醒、全量处理”的方式,避免了重复事件通知,也防止了事件被漏掉。配合非阻塞 I/O,整个事件循环不会卡在某次 read 或 write 上。
连接不等于请求,空闲连接几乎零开销
- 百万连接里,绝大多数是 HTTP keepalive 或 WebSocket 的长连接,处于空闲状态
- 这些空闲连接只挂在 epoll 的红黑树里,不占用栈空间、不分配线程、不触发回调
- 只有发生真实读写事件(比如客户端发来新请求),epoll_wait 才会把对应 fd 返回,Nginx 才启动处理逻辑
- 连接生命周期由 keepalive_timeout 控制,超时后自动关闭,不堆积僵尸连接
内存和系统资源全盘统筹,不让 epoll 单打独斗
epoll 再快,也扛不住内存乱分配或系统限制:
- 用 内存池(ngx_pool_t) 管理 request header、临时 buffer,避免频繁 malloc/free 和碎片
- 连接结构体 ngx_connection_t 控制在 200–300 字节,不含业务数据,轻量可扩展
- 必须调大系统级参数:ulimit -n(文件描述符上限)、fs.file-max、net.core.somaxconn
- 启用 multi_accept on,让一次 epoll_wait 返回后尽可能多地 accept 新连接,减少系统调用次数
本质上,epoll 是 Linux 提供的高效就绪通知工具,而 Nginx 的高并发能力,来自它对这个工具的克制使用和全局协同——事件驱动是骨架,非阻塞是神经,内存池是血液,系统调优是地基。四者缺一不可。











