nginx异步事件驱动架构通过ngx_connection_t统一承载连接状态、红黑树调度超时、非阻塞i/o分段推进,状态变化由内核事件触发而非轮询更新;每个连接复用预分配结构体,全程零重建、零阻塞、零主动刷新。

Nginx 异步事件驱动架构不靠轮询或线程等待来更新连接状态,而是把每个连接的生命周期完全纳入事件系统——状态变化即事件就绪,事件就绪即触发回调,整个过程由 ngx_connection_t 结构体统一承载、红黑树统一调度、非阻塞 I/O 分段推进。
连接状态由 ngx_connection_t 实时维护
每个活跃连接在 worker 启动时就从预分配的连接池中取出,对应一个 ngx_connection_t 实例。它不是临时对象,而是贯穿连接始末的状态容器:
- 记录 socket fd、读写事件注册状态(EPOLLIN/EPOLLOUT)、当前处理阶段(如“正在读请求头”“等待 upstream 响应”)
- 存储读写缓冲区指针、已接收字节数、已发送字节数、超时时间戳
- 标记 keepalive 状态、instance 标志(防止 TIME_WAIT 复用导致的串话)
- 与 HTTP request 结构(
ngx_http_request_t)通过指针关联,但二者生命周期可分离(例如长连接复用时 request 被释放而 connection 保留)
状态更新靠事件触发,而非主动轮询
连接的任何状态跃迁都由内核通知驱动:
- 新连接到来 → epoll 返回监听 socket 就绪 → 触发
ngx_event_accept→ 更新连接为“已 accept,等待 recv” - 客户端发来数据 → epoll 返回该 socket 的 EPOLLIN → 触发
ngx_http_read_request_header→ 更新为“正在解析 header” - 请求体未读完但缓冲区满 → recv 返回 EAGAIN → 不退出,仅保持 EPOLLIN 注册 → 状态仍为“读取中”,等下次就绪
- send 缓冲区满 → send 返回成功字节数小于待发量 → 注册 EPOLLOUT → 状态切为“等待可写”,后续 EPOLLOUT 就绪再续发
超时与空闲状态由红黑树统一管理
所有连接的读写超时、keepalive 超时、proxy 超时,都被抽象为定时器节点,插入全局红黑树:
- 每次
epoll_wait的超时值取自红黑树最小超时节点,避免空等 - 超时到期时,事件循环直接遍历对应连接,执行关闭、重试或清理逻辑
- 空闲连接不消耗 CPU:没事件、没超时,
epoll_wait阻塞等待,连接结构体静默驻留内存,零开销
状态复用避免重建开销
- keepalive 连接关闭 request 后,
ngx_connection_t不释放,清空业务字段后直接复用于下一个请求 -
ngx_http_request_t在请求结束时归还 slab 内存池,但连接层状态(socket、buffer、超时设置)持续有效 - 同一连接上多个请求的状态切换,只改指针和标志位,不 malloc/free,无锁竞争
本质上,Nginx 不“更新状态”,它让状态随事件自然演进——你看到的“连接已就绪”“请求已超时”“响应正发送”,都是某个事件回调执行后的结果,而不是某处代码在后台默默刷新字段。











