Nginx在Linux下默认使用epoll的边缘触发(ET)模式,因其仅在fd状态变化时通知一次,减少epoll_wait无效返回和上下文切换,配合非阻塞I/O与完整读写循环可提升高并发性能。

Nginx 默认使用 epoll 作为 Linux 下的事件驱动模型,而其默认行为是 边缘触发(ET, Edge-Triggered) 模式。在高并发、高负载场景下,正确理解并利用 ET 特性,能显著减少系统调用开销、提升事件响应效率,但前提是必须配合非阻塞 I/O 和完整的读写循环逻辑。
为什么边缘触发更适合高负载下的 Nginx
边缘触发只在文件描述符状态发生“变化”时通知一次(比如从不可读变为可读),之后即使还有数据可读,也不会重复通知。这避免了水平触发(LT)下频繁唤醒进程检查就绪状态的开销。在万级连接、短连接密集的场景中,ET 能大幅降低 epoll_wait 的无效返回次数和上下文切换频率。
- 减少内核到用户空间的事件拷贝次数
- 降低 CPU 在事件分发上的空转消耗
- 更利于 Nginx 的单线程多路复用模型发挥吞吐优势
必须配合非阻塞 socket 和完整读写循环
ET 模式下,若不一次性处理完所有可用数据,就可能错过后续通知,导致连接“卡住”。Nginx 内部已严格遵循该原则:所有 socket 均设为非阻塞(O_NONBLOCK),并在每个事件回调中循环调用 recv/send 直至返回 EAGAIN/EWOULDBLOCK。
- 读数据时:持续 read() 直到返回 -1 且 errno 为 EAGAIN
- 写数据时:持续 write() 或 send() 直到返回 -1 且 errno 为 EAGAIN;未写完的数据缓存到 connection->buffer 中,并注册写事件等待下次触发
- 不能依赖一次 read/write 完成全部收发,这是 ET 正确性的前提
epoll ET 模式对 Nginx 配置无直接开关,但受底层影响
Nginx 不提供显式配置项来开启/关闭 ET,它在初始化 epoll 实例时自动使用 EPOLLET 标志。但以下因素会影响 ET 是否真正生效:
- 运行环境必须是支持 epoll 的 Linux 内核(2.6+)
- worker_connections 设置需合理,避免 fd 耗尽导致 accept 失败或 fallback 到低效模型
- 确保没有第三方模块错误地将 socket 改为阻塞模式
- tcp_nodelay、tcp_nopush 等优化选项虽不改变 ET 行为,但能减少小包延迟,放大 ET 的响应优势
调试与验证 ET 是否正常工作
可通过 strace 观察 Nginx worker 进程的系统调用行为:
- 执行 strace -p $(pgrep nginx | head -1) -e epoll_wait,epoll_ctl -s 100,查看 epoll_ctl 是否带 EPOLLET 标志
- 对比高负载下 epoll_wait 的平均返回事件数:ET 模式下单次返回事件数通常更高,且空转率更低
- 若发现大量重复的可读/可写通知,可能是某处未按 ET 要求循环处理,需检查自定义模块或 Lua 脚本逻辑










