7.4.2 sendfile与高效文件传输

sendfile与高效文件传输#

原理与收益#

sendfile 让内核直接在文件系统缓存与网卡缓冲区间传输数据,减少用户态参与、降低拷贝与上下文切换,适合静态文件的大吞吐分发。

文章图片

预期收益
- CPU 占用下降
- 大文件下载吞吐提升
- 延迟降低(尤其高并发)

环境检查与启用步骤#

sendfile 为内核能力,不需额外安装,需确保内核与 Nginx 编译支持。

1) 检查 Nginx 编译参数

nginx -V 2>&1 | grep -o 'with-file-aio\|with-pcre\|with-http_gzip_static_module'

2) 检查系统内核版本

uname -r

3) 配置并验证
文件路径:/etc/nginx/nginx.conf

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;

    server {
        listen 80;
        server_name static.example.com;

        location /static/ {
            root /data/www;
            # 大文件禁用压缩,避免 sendfile 被绕过
            gzip off;
        }
    }
}

4) 语法检查与重载

nginx -t
systemctl reload nginx

预期效果
- 静态文件响应速度提升
- nginx -t 返回 ok,访问 /static/large.iso 能稳定下载

关键参数与命令解释#

  • sendfile on;:开启零拷贝传输
  • tcp_nopush on;:合并包头,减少小包
  • tcp_nodelay on;:小响应低延迟
  • keepalive_timeout 65;:控制长连接空闲时间

示例:对小文件与大文件差异化优化#

http {
    sendfile on;

    # 小文件优先低延迟
    location ~* \.(css|js|png|jpg)$ {
        root /data/www;
        tcp_nodelay on;
        tcp_nopush off;
        expires 7d;
    }

    # 大文件优先吞吐
    location /download/ {
        root /data/www;
        tcp_nodelay off;
        tcp_nopush on;
        sendfile on;
    }
}

性能验证与监控#

1) 观察系统调用

sudo strace -p $(pidof nginx | awk '{print $1}') -e trace=sendfile -tt

预期:出现 sendfile(...) = N 表示启用生效

2) 对比响应耗时

curl -o /dev/null -s -w 'time_total=%{time_total}\n' http://static.example.com/download/big.iso

3) 监控磁盘与网络吞吐

iostat -xm 1 3
sar -n DEV 1 3

常见问题排查#

  • 下载文件损坏/大小不一致
    处理:临时关闭 sendfile 验证
    nginx sendfile off;
    原因:旧内核或第三方模块兼容问题

  • 小文件响应变慢
    处理:对小文件关闭 tcp_nopushsendfile
    nginx location ~* \.(css|js)$ { sendfile off; tcp_nopush off; }

  • 反向代理无提升
    原因:sendfile 仅对静态文件直读有效
    处理:确认 root 直读,或改用 proxy_cache 缓存

练习#

1) 在测试环境对同一大文件开启/关闭 sendfile,对比 curl 下载时间。
2) 使用 strace 观察 sendfile 系统调用是否出现。
3) 设计一个包含小文件与大文件的虚拟主机,分别设置不同的 tcp_nopush/tcp_nodelay 组合,记录效果。