nginx 的 event loop 通过非阻塞 socket、内核事件通知(epoll/kqueue/iocp)、显式状态管理和阶段化 handler 实现异步非阻塞,无协程或线程切换,依赖 eagain 处理和红黑树定时器统一调度。

Nginx 的 Event Loop 实现异步非阻塞处理,核心不是靠协程或线程切换,而是靠操作系统事件通知机制 + 状态机驱动的协作式分阶段执行。它不等数据,只响应就绪;不占线程,只用状态;不靠挂起,靠主动让出。
依赖 epoll/kqueue 等内核事件通知机制
Linux 下默认使用 epoll,FreeBSD 用 kqueue,Windows 用 IOCP。这些机制允许 Nginx 单 worker 同时监听数万连接,而无需轮询:
- 调用 epoll_wait() 时,内核在有 socket 就绪(可读/可写/出错)时才返回,避免空转
- 每个客户端连接对应一个非阻塞 socket,注册到当前 worker 的 epoll 实例中
- 当新连接到达,accept() 后立即设为非阻塞,并注册 EPOLLIN;发送数据时若遇 EAGAIN,则临时注册 EPOLLOUT 等待可写
所有 I/O 操作都设为非阻塞并配合 EAGAIN 处理
非阻塞不是“立刻完成”,而是“立刻返回”——无论读写是否真正发生,系统调用都不会卡住进程:
- recv() 或 send() 返回 EAGAIN/EWOULDBLOCK,说明当前无数据可读或缓冲区已满,此时不等待,直接退出当前 handler
- 退出前,把该请求的状态(如 phase_handler、read_event_handler)保存在 ngx_http_request_t 中
- 同时重新注册对应事件(如 EPOLLIN 或 EPOLLOUT),让事件循环下次调度时继续处理
用状态机驱动多阶段请求处理
HTTP 请求被拆成多个 phase(如 NGX_HTTP_POST_READ_PHASE、NGX_HTTP_CONTENT_PHASE),每个阶段可中断、可恢复:
- 模块通过返回 NGX_AGAIN 或 NGX_DECLINED 主动交还控制权,不阻塞整个 worker
- 例如 proxy 模块转发请求后,设置 r->write_event_handler = ngx_http_upstream_handler,然后 return,即完成一次“中断”
- 等 upstream socket 可读时,事件触发回调,从 request 结构中取出之前保存的状态,继续解析响应头或转发 body
定时器与超时机制嵌入事件循环
超时不是额外线程维护,而是和 I/O 事件统一调度:
- 所有超时事件(如 client_header_timeout、send_timeout)存于红黑树,每次进入 epoll_wait 前计算最小超时值,作为 timeout 参数
- epoll_wait 超时返回后,Nginx 扫描红黑树,触发已到期的超时逻辑(如关闭慢连接)
- 这样既保证及时性,又避免独立定时器线程开销
整个过程没有栈保存、没有上下文切换、不依赖语言级协程。它靠的是:非阻塞 socket + 内核事件通知 + 显式状态管理 + 阶段化 handler 设计。高效,但也要求所有模块严格遵守这一模型——一旦出现同步阻塞操作(如大文件 read()、阻塞 DNS 查询),就会拖垮整个 worker。











