nginx采用就绪驱动的动态回调网络而非线性流水线,将http请求拆解为可注册、可中断、可超时的原子事件,由单事件循环统一调度;监听套接字注册epoll非阻塞等待连接,通过multi_accept和accept_mutex优化接入;请求生命周期分阶段回调驱动解析、匹配、转发,i/o全非阻塞;超时由红黑树统一纳管,实现“有事快办、无事小睡”;日志、ssl、lua等需异步适配以避免阻塞事件循环。

nginx 的事件处理不是线性执行的流水线,而是一张由就绪状态触发的动态回调网络。它把一次 HTTP 请求从建立到关闭的全过程,拆解成多个可独立注册、可随时中断、可精准超时的原子事件,全部交由一个紧凑的事件循环统一调度。
监听套接字就绪:连接接入的第一道闸口
worker 进程启动时,已将监听 socket 注册进 epoll,并设为非阻塞模式。当新连接到达,内核通知该 socket 可读,事件循环立即调用 accept 处理逻辑:
- 启用 multi_accept on 时,会一次性 accept 所有已完成三次握手的连接,减少反复进出事件循环的开销
- accept_mutex on(默认)确保同一时刻仅一个 worker 尝试 accept,避免“惊群”唤醒大量进程空转
- 每个新连接绑定唯一 instance 标志,防止刚关闭的 socket 被快速复用后,旧请求数据误入新连接
HTTP 请求生命周期:阶段化回调驱动解析与转发
连接建立后,Nginx 不再等待完整请求到达,而是按需分阶段响应:
- 收到首个数据包后,注册读事件,仅解析请求行和头部——全部在内存中完成,不涉及磁盘或网络等待
- 头部解析完毕即触发 location 匹配、变量展开、rewrite 执行等回调,每步轻量且无 I/O 阻塞
- 静态资源直接走 sendfile(),由内核在磁盘页缓存与 socket 缓冲区间零拷贝传输
- 动态请求则通过 upstream 模块发起反向代理,连接复用 keepalive,避免重复 TLS 握手与 TCP 慢启动
- 所有 socket I/O 操作均为非阻塞:recv() 遇 EAGAIN 立即返回;send() 只发当前缓冲区允许字节数,剩余挂起并注册 write event 待下次可写再续
超时与资源释放:红黑树统一纳管的被动治理
每个连接的各类超时并非靠独立线程轮询,而是纳入全局红黑树进行统一管理:
- client_header_timeout、client_body_timeout、keepalive_timeout 等均转化为定时器节点,插入红黑树
- 每次 epoll_wait() 的超时参数,取自红黑树中最早到期的定时器时间,实现“有事快办、无事小睡”
- 定时器到期即触发对应连接的清理逻辑:关闭空闲连接、中断卡顿请求、重试失败 upstream
- 这种设计让空闲连接完全不消耗 CPU,真正实现“连接数高但负载低”
系统级协同:避免事件驱动被下游同步操作拖垮
事件循环再高效,也掩盖不了阻塞式下游带来的性能断层:
- 日志写入必须启用 buffered 或异步日志模块,否则 access_log 同步刷盘会成为 I/O 瓶颈
- SSL 握手应配置 ssl_session_cache 和合理 ssl_buffer_size,降低加解密重复开销
- Lua 脚本中禁止使用 http.request 等同步调用,必须改用 cosocket 或将耗时逻辑移至后端服务
- worker_processes auto 与 worker_cpu_affinity auto 让进程数匹配物理核心数,减少上下文切换
整条链条的本质,是把“等待”变成“注册”,把“阻塞”变成“回调”,把“串行依赖”变成“就绪驱动”。它不追求单次请求最快,而是让单位时间内处理的就绪事件最多——这才是支撑十万并发仍保持毫秒级响应的底层逻辑。











