nginx事件驱动架构采用同步、顺序执行的回调机制,由worker进程主动遍历epoll就绪列表并调用ev->handler(ev),避免线程切换与上下文丢失;事件、定时器、连接生命周期均通过ngx_event_t与ngx_connection_t指针链统一调度,各阶段handler按状态迁移推进,遇eagain即暂停等待下一次就绪。

Nginx 事件驱动架构不靠多线程“堆资源”,而是用一套轻量、可控的回调机制,把每个 I/O 动作和定时任务都变成可调度、可预测的函数调用。它的优化不在“并发数量”本身,而在如何让有限的 worker 进程不空转、不阻塞、不错过任何就绪事件。
回调不是被动触发,而是主动、同步、顺序执行
操作系统(如 epoll)只负责通知“哪些 fd 就绪了”,并不调用你的业务逻辑。Nginx 拿到就绪列表后,自己遍历、校验、再逐个调用 ev->handler(ev) —— 这个调用是同步的、在 worker 主线程中完成的,没有栈切换、没有上下文丢失。这意味着:
- 无需锁保护共享状态(只要 handler 不跨事件共享数据)
- 调试和追踪更直观:一次 handler 调用对应一个明确的事件阶段(比如刚 accept、刚读到请求头、刚写完响应体)
- 不会出现“回调嵌套过深”或“异步栈混乱”,所有逻辑都在清晰的控制流里
回调函数绑定连接与请求生命周期,避免内存泄漏
每个 ngx_event_t 都通过 ev->data 指向对应的 ngx_connection_t,而 connection 又可能挂载 ngx_http_request_t。这种指针链不是临时传参,而是贯穿整个请求生命周期的“上下文锚点”:
- accept 事件的 handler(ngx_event_accept)创建 connection,并初始化其读事件 handler 为 ngx_http_init_request
- 后续读取请求行时,handler 切换为 ngx_http_process_request_line,它直接从 ev->data 找到 connection,再从中取出 request 结构
- 请求结束时,清理逻辑也通过同一 event 触发,确保 connection 和 request 内存被统一释放
定时器和清理事件也走同一回调路径,统一调度无例外
你写的 ngx_add_timer() 并不会启动新线程,也不会注册内核回调。Nginx 把定时器也当成一种“事件”,用红黑树管理超时时间,在每次事件循环开始前调用 ngx_event_expire_timers,把超时的 event 标记为就绪,然后照常放进 handler 遍历队列:
- 长连接超时?→ 触发 ngx_http_keepalive_handler,决定是否关闭
- upstream 代理等待超时?→ 触发 ngx_http_upstream_timeout,快速失败并返回错误
- 空闲 connection 清理?→ 触发 ngx_close_idle_connection,回收资源
回调之间靠状态迁移推进,不依赖阻塞等待
一个 HTTP 请求不是由一个 handler 一口气做完的,而是拆成多个小阶段,每个阶段完成后,主动设置下一个 handler 并等待下一次事件就绪:
- 刚建立连接 → handler = ngx_http_init_request(只读请求行)
- 读到完整请求行 → 解析 method/uri,分配 request 结构,设置 handler = ngx_http_process_request_headers
- 读完 header → 开始转发或本地处理,可能设置 write handler 或 upstream handler
- 每个 handler 返回前,都确保 socket 处于非阻塞模式,遇到 EAGAIN 就停住,等下次可读/可写事件再继续











