nginx 的非阻塞 i/o 通过“不等、不占、不卡”实现高并发:系统调用立即返回,依赖 epoll/kqueue 等事件机制通知就绪,将请求拆解为异步状态机,并配超时与资源限制兜底。

Nginx 的非阻塞 I/O 不是靠“加速读写”来避免阻塞,而是靠“不等、不占、不卡”——发起系统调用后立刻返回,把等待交给内核通知,自己转身处理别的事。
非阻塞调用:读写不挂起进程
所有 socket 都设为 non-blocking 模式。调用 recv() 或 send() 时:
- 若内核缓冲区有数据可读 / 有空间可写,操作立即完成,返回字节数
- 若暂无数据或缓冲区满,不等待,直接返回 EAGAIN 或 EWOULDBLOCK
- worker 进程不会停在这一步,而是继续执行事件循环中的下一个就绪任务
事件驱动协同:只在真正就绪时才动手
非阻塞本身不是银弹,必须和操作系统级事件机制配合:
- Linux 下使用 epoll,FreeBSD/macOS 用 kqueue
- Nginx 把成千上万个 socket 统一注册进 epoll 监听表,由内核代为监控状态变化
- 仅当某个 socket 触发 EPOLLIN(可读)或 EPOLLOUT(可写)时,Nginx 才对它执行非阻塞的 recv/send
- 没有“轮询每个连接试一遍”的忙等待,CPU 几乎全用于有效处理
请求生命周期拆解为异步状态机
一个 HTTP 请求被分解为多个独立状态,每个状态只做一件事,完成后立即推进或等待事件:
- TCP 连接建立 → 触发 accept,注册读事件
- 客户端慢发 header → 每次 read 返回 EAGAIN 后,继续监听该 socket 的 EPOLLIN,不影响其他连接
- 转发请求到 upstream → 当前连接挂起,状态机转入 “waiting for upstream”,事件循环照常调度其余连接
- 后端响应到达 → 触发读事件;发送响应时若 send 返回 EAGAIN,则注册 EPOLLOUT,等可写再续发
超时与资源限制兜底防堆积
非阻塞 + 事件驱动解决的是“不被拖住”,但需配置防止慢连接长期滞留:
- client_header_timeout 10; 和 client_body_timeout 10;:防 Slowloris 类攻击
- send_timeout 60;:两次 write 间隔超时即断连,避免低速下载长期占连接
- keepalive_timeout 75;:及时回收空闲长连接
- reset_timedout_connection on;:用 RST 快速释放内核连接状态,不等 FIN 交互
本质上,Nginx 不追求让慢连接变快,而是确保慢连接的存在,完全不影响其他请求的接收、解析、转发和响应。一个 worker 处理 10 万个连接时,其中 9.9 万个处于“等待就绪”状态,既不耗 CPU,也不抢调度时间片,更不阻塞任何一条路径。











