nginx的event loop是worker进程内同步执行的单线程主循环,通过for(;;)持续运行,以“不等、不阻、不创建”方式管理连接;其循环分三阶段:调用epoll_wait等待就绪事件、将事件转为内部结构入队、同步执行handler;事件按需动态注册,定时器与清理任务统一纳入同一循环调度。

Nginx 的 Event Loop 不是异步回调框架里的“事件循环”,也不是靠线程池或协程调度,而是一个由 worker 进程自主控制、同步执行的单线程主循环。它用最朴素的方式——一个持续运行的 for(;;) 循环——把成千上万个连接管起来,核心在于“不等、不阻、不创建”。
Event Loop 运行在独立 worker 进程中
每个 worker 是一个标准 Unix 进程,内部只有单一执行流:
- 不为每个连接分配线程或栈空间
- 不依赖操作系统调度器来回切换上下文
- 所有 I/O 处理、HTTP 解析、响应生成都在这一个线程里顺序完成
这种设计直接避开多线程模型的上下文切换开销和锁竞争问题。
一次循环干三件事:等、搬、调
整个循环逻辑可拆解为三个明确阶段:
-
等:调用
epoll_wait()(Linux)或其他等效系统调用(如kqueue),批量等待多个 fd 就绪;超时时间由定时器动态计算,兼顾响应延迟与 CPU 节能 -
搬:内核返回就绪事件列表后,Nginx 不立刻处理业务,而是把每个
epoll_event转换成内部ngx_event_t结构,放进就绪队列 -
调:遍历就绪队列,依次同步执行
ev->handler(ev);handler 返回前可决定是否注册新事件(比如读完 header 后挂 body 读 handler)、是否关闭连接
这个过程全程同步,无中断、无回调嵌套、无隐式调度。
事件注册是按需、分阶段、带上下文的
Nginx 不是一次性注册所有事件,而是随连接生命周期动态挂载:
- 启动时,监听 socket 注册读事件,handler 是
ngx_event_accept,专用于 accept 新连接 - accept 到新连接后,为其读事件绑定
ngx_http_process_request_line,开始解析 HTTP 请求行 - 收到完整 header 后,可能注册 body 读事件;需要发响应时,才为写事件注册
ngx_http_writer,并触发epoll_ctl(EPOLL_CTL_MOD)更新内核事件表 - 每个
ngx_event_t都携带data字段,指向对应的ngx_connection_t或ngx_http_request_t,确保 handler 执行时总有完整上下文
定时器、清理任务也跑在同一循环里
- 定时器不是单独线程,而是由红黑树维护的超时节点,在每次循环开始前检查是否到期
- 连接超时(如
client_header_timeout)、缓存清理、日志刷盘等任务,都作为“定时事件”统一纳入调度 - 所有事件类型共享同一套就绪队列和 handler 调用机制,逻辑高度一致
这种结构让 Nginx 在单 worker 下轻松支撑数万并发连接,关键不在“快”,而在“省”——省线程、省上下文、省内存、省调度。











