非阻塞i/o通过挂起连接、登记写事件并等待内核通知续发,避免worker阻塞;结合sendfile零拷贝、缓冲区与超时协同、epoll/kqueue就绪驱动机制,全面提升吞吐与响应及时性。

非阻塞 I/O 本身不加快单次 send() 的速度,而是让响应报文发送过程不再“卡住”整个 worker,从而提升整体吞吐和响应及时性。关键在于:数据发不出去时不空等,而是挂起连接、登记事件、等内核通知再续发。
发送遇阻时自动转入写事件队列
当 socket 发送缓冲区已满(比如客户端接收太慢或网络拥塞),send() 立即返回 EAGAIN/EWOULDBLOCK,Nginx 不重试也不等待,而是把该连接加入内部 write event 队列,并注册 EPOLLOUT(Linux)或 EV_WRITE(BSD/macOS)。下次 epoll/kqueue 返回“可写”事件时,再触发续发逻辑——整个过程 worker 始终可调度其他请求。
零拷贝路径大幅减少系统调用与内存复制
对静态文件响应,启用 sendfile on 后,内核直接从 page cache 将数据写入 socket 缓冲区,跳过用户态内存拷贝:
- 省掉一次 read() + 一次 write() 系统调用
- 避免两次 CPU 拷贝(磁盘→用户内存→socket 缓冲区)
- 配合 tcp_nopush on,让 sendfile 数据尽量填满 TCP 报文段,降低小包数量
缓冲区与超时协同防“慢客户端拖垮服务”
非阻塞只解决“不等”,但需策略防止连接长期滞留:
- send_timeout 控制两次 write 之间的最大间隔(如设为 30s),超时即断连
- client_body_buffer_size 和 proxy_buffer_size 设合理上限,避免大响应体在内存中堆积
- 禁用 proxy_buffering off 在高延迟上游场景下易导致事件循环被阻塞,建议开启缓冲并调大 proxy_buffers
事件分发机制确保“就绪才动”
Nginx 不轮询每个连接是否可写,而是依赖 epoll/kqueue 的高效就绪通知:
- 所有 socket 默认设为非阻塞,仅在 EPOLLOUT 触发时才尝试 send()
- multi_accept on 允许单次 epoll_wait() 批量获取多个可写事件,减少系统调用频次
- 确保配置了 use epoll(Linux)或 use kqueue(BSD/macOS),避免退化为低效的 select/poll











