nginx高性能源于单worker进程+同步非阻塞i/o+epoll事件通知:不依赖多线程堆资源,而是通过状态机驱动事件循环,对每个连接仅在就绪时处理,空闲时不耗cpu,配合non-blocking socket与内核高效协同,实现万级并发低开销。

Nginx 的高性能网络响应不靠堆资源,而靠一套轻量、确定性强的运行逻辑:单 worker 进程 + 同步非阻塞 I/O + 内核事件通知机制(如 epoll)。它并不使用真正意义上的异步 I/O(如 io_uring),但通过精准的状态管理与事件分发,把每个连接的等待成本压到最低。
事件驱动:用一个循环管数万连接
Nginx worker 不为每个请求开线程,而是靠事件循环持续监听所有活跃连接的状态变化。当内核通过 epoll 告知“某个 socket 可读”或“缓冲区可写”,worker 就立即调用对应模块处理——比如解析请求头、读取请求体、查找文件、组装响应。整个过程无阻塞、无等待、不切换上下文。
- epoll 使用红黑树管理监听 fd,就绪事件走链表,时间复杂度接近 O(1),远优于 select/poll 的轮询扫描
- 每个连接在不同阶段(等待请求、读取中、缓存查找、发送响应)都由状态机驱动,只做当前必须的动作,完成后立刻挂起
- 空闲连接不消耗 CPU,仅占用少量内存;连接数升至 10 万时,worker 仍能稳定轮转
非阻塞 I/O:让系统调用“秒返回”
所有 socket 都设为 non-blocking 模式。read() 或 send() 调用不会卡住进程——若数据未就绪或缓冲区满,立刻返回 EAGAIN/EWOULDBLOCK,worker 就转向处理其他就绪事件。这避免了传统阻塞模型中“一个慢连接拖垮全部”的风险。
- recv() 返回 0 表示对端关闭;返回 -1 且 errno 是 EAGAIN,说明暂时没数据,等下次 epoll 通知
- send() 写不完时,Nginx 会把剩余数据暂存到 connection 的 write buffer,并注册可写事件,后续再续发
- 配合 tcp_nopush 和 sendfile,还能减少内核态/用户态拷贝和小包发送次数
关键配置决定事件循环是否“干净”
哪怕模型再高效,错误配置也会悄悄引入同步阻塞,打断事件流。这些点最容易被忽略:
- proxy_buffering off 且 upstream 响应慢 → Nginx 被迫轮询等待,失去非阻塞优势
- auth_request 指向外部 HTTP 接口且未配缓存 → 默认同步等待校验结果,阻塞当前 worker
- log_format 中含 $request_time 本身不阻塞,但 access_log 未启 buffer 或磁盘过载,可能间接拖慢调度
- ssl_session_cache 未启用 shared → 每次 TLS 握手都要跑完整流程,耗时从毫秒级升至数十毫秒
真实延迟在哪?Nginx 很少是瓶颈
可观测的“百微秒响应”往往出现在极简路径:本地内存缓存命中、空响应返回、Unix socket 直连同机服务。而实际延迟多来自外部环节:
- DNS 解析未用 resolver valid=30s → 每次都阻塞查询
- 上游网络 RTT 高或后端应用处理慢(PHP/Python 等)
- 静态文件未启用 open_file_cache,反复 open/stat 系统调用
- TLS 加解密未启用 OCSP stapling 或硬件加速,握手耗时突增











