Nginx事件循环核心是ngx_process_events调用平台I/O多路复用(如epoll_wait)获取就绪事件,校验后执行ev->handler回调;handler由模块动态注册(如ngx_event_accept、ngx_http_init_request),通过ev->data绑定connection与request生命周期,并统一调度定时器与清理事件。

Nginx 的事件处理核心在于其基于 epoll(Linux)、kqueue(FreeBSD)或 select(兼容模式)等 I/O 多路复用机制构建的异步非阻塞循环,而“底层事件处理函数在循环中的回调与执行逻辑”本质上是指 ngx_process_events 及其后续调用链如何将就绪事件转化为具体的读写、定时器、清理等回调动作。
事件循环主干:ngx_process_cycle 中的 ngx_process_events
在 worker 进程中,主循环位于 ngx_process_cycle,每轮迭代调用一次平台相关的事件分发函数(如 ngx_epoll_process_events)。该函数完成三件事:
- 调用系统调用(如 epoll_wait)等待事件就绪,返回就绪事件数组(
events) - 遍历每个就绪事件,根据
ev->instance和ev->active等字段校验事件有效性,避免过期事件(stale event)误触发 - 对每个有效事件,调用其 ev->handler(ev) —— 这就是用户注册的事件回调函数入口,例如 ngx_http_read_request_handler 或 ngx_event_accept
回调函数的注册来源:从 listen 到 handler 绑定
事件回调不是硬编码的,而是由模块在初始化阶段动态挂载:
- HTTP 模块在 ngx_http_add_listening 中为监听 socket 创建
ngx_event_t,并把 ngx_event_accept 赋给rev->handler - 当新连接 accept 成功后,Nginx 为客户端 socket 创建读事件
rev,将其handler设为 ngx_http_init_request(初始读取请求行) - 后续 HTTP 请求解析过程中,可能切换 handler,例如进入长连接后设为 ngx_http_keepalive_handler
所有这些 handler 都是普通 C 函数指针,不涉及闭包或上下文捕获,依赖 ev->data(通常指向 ngx_connection_t)来获取连接上下文。
事件执行的上下文保障:connection 与 request 的生命周期绑定
虽然事件回调是裸函数调用,但 Nginx 通过严格的状态管理和内存归属保证执行安全:
-
ev->data指向ngx_connection_t,其中包含读写事件指针(read/write)、连接池(pool)、以及可选的data字段(常用于挂ngx_http_request_t *) - HTTP 模块在 ngx_http_create_request 后,会把 request 挂到 connection 的
data字段,并在 request 销毁时清理 connection 的关联字段 - 定时器事件(
ngx_timer_expire)和清理事件(ngx_event_expire_timers)也统一走同一套ev->handler调度,只是 handler 类型不同(如 ngx_close_idle_connection)
关键细节:事件未就绪时的“空转”与优化
Nginx 不会忙等。当 epoll_wait 超时(由 timer 参数控制),它仍会检查定时器队列和延迟队列:
- 调用 ngx_event_expire_timers 扫描红黑树中到期的 timer,逐个执行其
ev->handler - 若启用了 accept_mutex,还可能尝试抢锁并触发 ngx_trylock_accept_mutex
- 最后调用 ngx_worker_process_cycle 的 posted 队列(如
ngx_posted_accept_events),执行延后处理的事件
这种设计使单次循环既能响应外部 I/O,也能驱动内部状态机(如超时关闭、负载均衡探测),无需额外线程或信号。









