Nginx在启用epoll时默认使用边缘触发(ET)模式;其events块通过use epoll;触发ET路径,multi_accept和worker_connections影响ET效能,内部已遵循非阻塞、循环读写等ET约束。

Nginx 的 events 块本身不直接控制边缘触发(ET)模式的底层调用,它只是向 epoll 等事件驱动机制传递配置意图;真正启用 ET 模式依赖于 Nginx 编译时启用了 epoll 支持,并在运行时由内核的 epoll_ctl() 系统调用自动以 ET 方式注册 socket 事件——前提是使用了 epoll 作为事件模型。
events 块如何间接影响 ET 行为
events 块中的配置项虽不显式声明“ET”,但会决定 Nginx 是否能进入 ET 工作路径:
-
use epoll; 是关键前提:只有显式指定
use epoll;,Nginx 才会在 Linux 上调用epoll_create()和epoll_ctl(EPOLL_CTL_ADD, ...),且默认以EPOLLET标志注册事件(即 ET 模式) -
multi_accept off; 或 on; 不改变 ET 语义,但影响单次 epoll_wait 返回后是否尽可能多地 accept 新连接——ET 模式下建议设为
on,避免因未及时处理完就绪连接而造成饥饿 -
worker_connections 设定单 worker 最大并发连接数,该值需 ≤ 系统
rlimit -n,否则部分连接无法被 epoll 监听,ET 的高效性无从谈起
ET 模式下必须配合的编程约束
Nginx 内部已遵循 ET 模式要求,但若你扩展模块或调试行为,需注意:
- socket 必须设为 非阻塞(O_NONBLOCK):ET 要求一次事件就绪后必须读/写到
EAGAIN/EWOULDBLOCK,否则可能永远无法再次触发就绪通知 - 读操作需循环直到返回
EAGAIN:例如在ngx_event_accept中,accept 必须持续调用直至失败;否则遗漏的连接不会被后续 epoll_wait 捕获 - 写事件需谨慎启用:ET 下写就绪不意味着可无限写,而是“内核发送缓冲区有空闲”。Nginx 通常只在有数据待发且之前 write 返回
EAGAIN后才重新 arm EPOLLOUT
为什么不用显式配置 ET?
Nginx 将 ET 视为 epoll 的最佳实践,默认启用,无需用户干预:
- LT(水平触发)在高并发下易产生重复事件通知,增加无谓系统调用开销
- ET 更契合 Nginx 的事件驱动架构:每个 socket 由一个 event 结构体长期持有,状态变更由事件回调驱动,而非轮询检查
- 源码中
src/event/modules/ngx_epoll_module.c在ngx_epoll_add_event里硬编码传入EPOLLET,只要用 epoll 就是 ET
验证当前是否运行在 ET 模式
可通过以下方式确认:
- 检查配置中是否有
use epoll;(Linux 环境下),且未被自动降级为poll或select - 运行
strace -p $(pgrep nginx) -e trace=epoll_ctl 2>&1 | grep EPOLLET,应能看到epoll_ctl(..., EPOLL_CTL_ADD, ..., EPOLLET) - 查看
/proc/中 epoll 对应 fd 的 flags 字段(需内核支持),ET 模式下含/fdinfo/ 0x80000(即 EPOLLET)










