nginx的非阻塞i/o与sendfile协同实现零拷贝:非阻塞i/o基于epoll/kqueue事件驱动,避免阻塞和上下文切换;sendfile将文件数据直接从磁盘fd送至socket fd,免用户态拷贝;二者结合提升静态文件服务的并发性能与吞吐。

Nginx 的 Non-blocking I/O 本身不等于零拷贝,但它为零拷贝(如 sendfile)提供了运行基础。真正实现零拷贝传输的是内核机制,而 Non-blocking 模式确保 Nginx 能在不阻塞进程的前提下,高效调度和触发这些内核能力。
Non-blocking I/O 是前提,零拷贝是内核能力,两者协同才生效
Nginx 默认使用 epoll(Linux)或 kqueue(BSD)等事件驱动模型处理连接。每个 worker 进程通过单线程事件循环监听成千上万个连接的“可读”“可写”事件。当一个静态文件响应需要发送时:
- 若启用了
sendfile on,Nginx 不会把文件内容读进用户态内存,而是直接向内核发起sendfile()系统调用; - 内核收到后,在页缓存(page cache)与 socket 缓冲区之间完成数据搬运,全程不经过用户空间;
- 此过程无需 CPU 拷贝、不分配用户态缓冲区,上下文切换也从 4 次减至 2 次;
- Non-blocking 特性保证:如果 socket 发送缓冲区暂不可用(如网络拥塞),
sendfile()返回EAGAIN,Nginx 就把该连接挂起,等下次“可写”事件再续传——不会卡住整个 worker。
零拷贝生效的关键条件必须满足
仅开启 Non-blocking 和 sendfile on 不够,以下任一不满足,Nginx 自动降级为普通 read/write:
- 文件类型合规:必须是 ext4/xfs/btrfs 上的常规文件;不支持设备文件、FIFO、NFSv3(部分旧版本)、加密文件系统(如 ecryptfs);
-
禁用用户态干预:不能启用
gzip on、gzip_static on、proxy_buffering on,也不能在access_by_lua_block中修改响应头或 body; -
路径解析正确:
location中避免alias与root混用导致文件未找到;SELinux/AppArmor 权限不足也会静默失败; -
TCP 优化配合:
tcp_nopush on启用后,内核会在 sendfile 完成后合并 TCP 包,避免小包泛滥;tcp_nodelay on则对交互类请求更友好。
实际配置建议(放在 http 或 server 块中)
sendfile on;tcp_nopush on;tcp_nodelay on;-
aio threads;(配合大文件异步读取) -
directio 4m;(对超大文件跳过 page cache,避免缓存污染)
注意:aio 和 directio 需配合 sendfile off 使用,二者互斥——directio 绕过 page cache,而 sendfile 依赖 page cache 复用,不能同时启用。
Non-blocking 让 Nginx 轻量调度,sendfile 让内核高效搬运,二者结合才是生产环境高并发静态服务的底层支柱。











