Nginx的高效并发依赖ET模式与非阻塞I/O、事件循环、回调驱动的严丝合缝配合:ET仅在状态变化时通知一次,倒逼Nginx循环读写至EAGAIN/EWOULDBLOCK,结合定时器驱动的事件循环实现万级连接的确定性分段处理。
异步边缘触发(ET)是 epoll 在 Nginx 中高效处理海量连接的关键机制,但它常被误解为“只要设 ET 就自动高性能”。实际上,Nginx 的真实能力来自 ET 模式与非阻塞 I/O、事件循环、回调驱动三者严丝合缝的配合。理解它,重点不在“边缘触发”本身,而在它如何迫使 Nginx 做出确定性、一次性、不遗漏的 I/O 处理决策。
边缘触发(ET)的本质约束:只通知一次状态变化ET 模式下,epoll 只在文件描述符(如 socket)的就绪状态**从无到有**时通知一次。比如:客户端发来 2KB 数据,内核缓冲区由空变非空,epoll_wait 返回该 fd;但如果你只 read 了 1KB,剩下 1KB 还在缓冲区,epoll 不会再次通知——除非新数据又抵达,再次触发“状态变化”。这和水平触发(LT)持续提醒完全不同。
这个特性倒逼 Nginx 必须做到:socket 必须设为非阻塞(O_NONBLOCK)
:否则在 ET 下 read/write 可能卡住,导致整个事件循环阻塞每次就绪后必须循环读/写直到 EAGAIN 或 EWOULDBLOCK:确保把当前缓冲区数据全部清空或写完,不遗留“半桶水”
不能依赖“下次还会提醒”,必须一次收干净或发干净Nginx 如何落实 ET 的一次性处理逻辑Nginx 在 accept 新连接后,立即将其 socket 设为非阻塞,并注册 EPOLLIN | EPOLLET。当该连接有数据可读时,事件 handler(如ngx_http_process_request_line)被调用。它的内部流程严格遵循 ET 要求:Nginx在宝塔面板中轻松管理Nginx高性能Web服务器。提供可视化配置反向代理、负载均衡、SSL证书及HTTP缓存功能,一键优化高并发性能,助您高效搭建稳定、快速的网站运行环境。
下载调用recv()读取请求头,若返回 >0,继续循环读,直到返回 -1 且 errno 为 EAGAIN/EWOULDBLOCK若读到完整请求行但未收完全部 body,会注册读事件并设置定时器,但不会等待“下次通知”,而是靠后续 epoll_wait 触发再续读写响应时同理:调用 send() 尽可能发送,遇到 EAGAIN 就暂停,等 epoll 再次通知 EPOLLOUT 后继续这种“激进读写 + 状态机推进”的方式,让单个 worker 进程无需切换上下文,就能在一次事件调度中完成多个连接的分段 I/O,是支撑万级并发的底层节奏。
ET 与事件循环、定时器的协同节拍Nginx 的事件循环不是裸跑 epoll_wait,而是一个带超时调度的精密节拍器。epoll_wait 的 timeout 值并非固定,而是动态计算自红黑树中最近定时器的剩余时间。这意味着:即使没有网络事件,epoll_wait 也会准时返回(超时),从而驱动定时器检查(如 keepalive 超时、read/write 超时)
ET 的“只通知一次”特性与定时器机制互补:ET 确保 I/O 不被重复扫描,定时器确保“沉默连接”不被遗忘所有事件(accept、read、write、timeout)最终都归一为 event->handler 函数调用,统一在单线程内串行执行,避免锁竞争为什么 Nginx 不用 LT?ET 带来的实际收益表面看 LT 更“宽容”,但对高并发场景是资源陷阱:LT 下,一个活跃连接若长期有数据残留(如大文件上传中的慢速客户端),会反复被 epoll_wait 返回,造成大量无效轮询ET 强制“状态跃迁思维”,天然适配 HTTP 请求-响应的阶段性特征:连接建立 → 读请求 → 解析 → 构造响应 → 写回 → 关闭/复用Nginx 源码中所有 I/O 路径都围绕 ET+非阻塞设计,包括 ngx_http_read_request_header、ngx_http_writer 等核心 handler,已深度绑定该模型
