Nginx采用事件驱动架构,通过预分配的ngx_connection_t结构体承载连接状态,以事件回调、内存复用和红黑树定时器实现无锁高效调度,各worker进程独立运行且仅共享内存协调全局策略。

Nginx 在异步事件驱动架构下不靠线程切换分发任务,也不维护传统意义上的“执行上下文”,而是用轻量级状态记录 + 事件回调 + 内存复用的方式实现高效调度与隔离。
事件就绪即分发,无主动轮询或排队
每个 worker 进程运行一个独立事件循环,调用 epoll_wait(Linux)等待内核通知哪些 socket 就绪。一旦返回就绪列表,Nginx 立即按 fd 查找对应 ngx_connection_t 结构体,并根据事件类型(EPOLLIN / EPOLLOUT / EPOLLERR)触发预注册的读/写/错误 handler。整个过程不排队、不等待、不分配新线程——所谓“分发”,就是函数指针跳转,开销极小。
- 新连接到达时,accept 处理器一次尽可能收完已排队连接,避免多次触发事件
- HTTP 请求头解析完成后,不等请求体收全,就提前注册后续读事件,进入“等待 body”状态
- 转发到 upstream 后,若响应未到,当前连接挂起,事件循环立刻转向处理其他就绪连接
连接状态由 ngx_connection_t 全程承载
每个活跃连接都绑定一个 ngx_connection_t 实例,它不是临时栈变量,而是从预分配的连接池中取出的固定结构体。该结构体里存着:socket fd、读写事件标志、当前 HTTP 解析阶段(如 reading header / parsing uri / waiting response)、输入输出缓冲区指针、超时时间戳、所属 upstream 连接引用等。所有这些信息构成该连接的“上下文”,但它不依赖线程本地存储(TLS),也不随函数调用压栈弹栈——它是内存地址固定的、可跨事件回调持续访问的状态容器。
- recv 返回 EAGAIN 时,不销毁连接,只保持 EPOLLIN 注册,下次就绪继续从上次断点读
- send 只发部分数据时,剩余字节留在 connection 的 output buffer 中,同时注册 EPOLLOUT
- keepalive 超时时间由红黑树统一管理,到期时直接调用 close 连接的回调,无需额外线程扫描
模块逻辑解耦,状态流转靠回调链而非堆栈
HTTP 模块、upstream 模块、proxy 模块等不共享执行栈,而是通过回调函数注册进事件系统。例如:ngx_http_core_run_phases 并非顺序执行全部阶段,而是在每个阶段末尾检查是否需挂起(如等待 upstream 响应),若需则保存当前 phase 编号和 request 引用,退出;待 upstream 数据就绪后,再从该 phase 继续推进。request 结构体本身也来自 slab 内存池,头部字段(如 method、uri)直接指针引用原始 buffer,不拷贝不重建。
- rewrite 阶段匹配 location 后,不立即跳转,而是设置 next_phase 指针,下次事件触发时才执行 access 阶段
- proxy_pass 发起 upstream 请求后,当前 request 进入 “upstream busy” 状态,connection 保持 open,但不再占用事件循环时间
- auth_request 子请求完成时,通过回调唤醒主请求,恢复其 phase 和 buffer 状态,继续后续流程
多 worker 间零共享执行上下文,仅靠共享内存协调全局策略
各 worker 进程完全独立运行,没有进程间通信(IPC)开销。它们共用监听 socket(通过 accept_mutex 或 SO_REUSEPORT 协调接入),但各自维护自己的连接池、事件队列、定时器红黑树和 slab 内存池。需要跨 worker 协同的功能(如限流 limit_req、连接数限制 limit_conn、SSL session cache)才使用共享内存段,且访问受原子指令或轻量锁保护,不影响事件循环主路径。
- worker A 接收的请求,其超时、缓冲、重试逻辑全部在 A 内闭环完成
- limit_req 使用共享内存中的滑动窗口计数器,但每次请求只做一次原子加减,不阻塞事件循环
- upstream 健康检查由单个 worker 异步发起,状态更新通过共享内存广播,其他 worker 读取时无锁



















