sendfile零拷贝
传统文件传输需要经历多次数据复制和上下文切换。sendfile 系统调用允许数据直接在内核空间传输,显著减少 CPU 和内存带宽消耗。
工作原理
传统 read/write 方式
nginx
磁盘 → 内核缓冲区 → 用户缓冲区 → Socket 缓冲区 → 网卡
4 次上下文切换,4 次数据复制。
sendfile 零拷贝方式
nginx
磁盘 → 内核缓冲区 → 网卡(通过 DMA 和 gather DMA)
2 次上下文切换,2 次数据复制(Linux 2.6+ 可进一步减少)。
基本配置
启用 sendfile
nginx
http {
sendfile on;
server {
listen 80;
root /var/www/html;
location /files/ {
# 自动使用零拷贝传输
}
}
}
sendfile在http、server或location块均可配置。静态文件服务器建议全局开启。
配合 tcp_nopush
Linux 下的最佳组合
nginx
http {
sendfile on;
tcp_nopush on;
}
tcp_nopush on 的效果:
- 配合 sendfile 使用,数据包攒满后再发送
- 减少网络包数量,提高吞吐量
- 可能增加最后一个数据包的延迟
tcp_nopush仅在sendfile on时生效。FreeBSD 下对应TCP_NOPUSH,Linux 下对应TCP_CORK。
配合 tcp_nodelay
动态内容优化
nginx
location /api/ {
proxy_pass http://backend;
tcp_nodelay on; # 动态内容不延迟发送
}
location /static/ {
sendfile on;
tcp_nopush on; # 静态内容攒包发送
}
tcp_nodelay禁用 Nagle 算法,小数据包立即发送。动态内容追求低延迟应开启,静态内容追求吞吐量应使用tcp_nopush。
不适用场景
何时不应该使用 sendfile
text
# 反向代理场景通常不需要 sendfile
location /api/ {
proxy_pass http://backend;
# sendfile off; # 默认就是 off,无需显式设置
}
# 大文件下载可开启 aio 配合
location /downloads/ {
sendfile on;
aio threads;
directio 4m;
}
- 反向代理:数据来自后端服务器,不在本地磁盘
- 小文件:sendfile 优势不明显
- NFS 挂载文件:某些 NFS 实现不支持 sendfile
与 aio 配合
异步 I/O 增强
text
location /video/ {
sendfile on;
aio threads;
directio 4m; # 大于4MB的文件使用直接I/O
}
aio threads使用线程池实现异步 I/O,directio设定使用直接 I/O 的文件大小阈值,绕过内核页缓存。
要点总结
sendfile on启用零拷贝,减少数据复制和上下文切换- 静态文件服务必开
sendfile+tcp_nopush - 动态内容使用
tcp_nodelay降低延迟 sendfile和tcp_nopush配合实现攒包发送- 反向代理场景不需要 sendfile(数据不在本地磁盘)
- 大文件可配合
aio threads和directio进一步提升
📝 发现内容有误?点击此处直接编辑