Nginx 的非阻塞 I/O 通过 non-blocking socket、epoll/kqueue 事件通知和异步状态机实现高效并发,辅以超时与资源限制防堆积。

Nginx 的非阻塞 I/O 不是绕开系统调用,而是让系统调用“不等、不占、不卡”——调用立刻返回,把等待交给内核通知,自己转身处理别的事。它规避的不是系统调用本身,而是传统阻塞模型下因等待导致的资源浪费和级联阻塞。
所有 socket 都设为 non-blocking 模式
这是基础前提。recv() 和 send() 不再挂起进程:
- 有数据可读 / 有空间可写 → 立即完成,返回字节数
- 暂无数据或缓冲区满 → 立即返回
EAGAIN或EWOULDBLOCK,worker 进程不在此停顿,直接进入事件循环处理下一个就绪任务
用 epoll/kqueue 替代轮询,消除忙等待开销
Linux 下用 epoll,FreeBSD/macOS 用 kqueue,它们让内核代为监控成千上万个 socket 状态:
- Nginx 把所有连接注册进监听表,只在真正就绪(如
EPOLLIN或EPOLLOUT)时才被通知 - 没有遍历每个 fd 判断状态的
O(n)轮询,也没有空转 CPU 的忙等待 - 内核通知一到,Nginx 就对那个就绪 socket 执行一次非阻塞
recv/send,动作短、响应快
把请求拆成异步状态机,每个阶段只做一件事
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;:及时回收空闲长连接,释放 fd 和内存 -
reset_timedout_connection on;:对超时连接发 RST,快速清理内核连接状态
不复杂但容易忽略


















