全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-20 6 分钟 ✍️ juanwangdev

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/ {
            # 自动使用零拷贝传输
        }
    }
}

sendfilehttpserverlocation 块均可配置。静态文件服务器建议全局开启。

配合 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 降低延迟
  • sendfiletcp_nopush 配合实现攒包发送
  • 反向代理场景不需要 sendfile(数据不在本地磁盘)
  • 大文件可配合 aio threadsdirectio 进一步提升

📝 发现内容有误?点击此处直接编辑

← 上一篇 gzip压缩优化
下一篇 → worker进程与CPU绑定
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库