启用sendfile需配置、系统支持与规避退化行为三者齐备:显式开启sendfile并作用于静态资源location,禁用gzip/etag/Range等破坏零拷贝的特性,确认内核≥2.4及网卡支持SG-DMA,调优TCP缓冲区与tcp_nopush,并配合open_file_cache及本地文件系统。

在 Nginx 中启用 sendfile 并真正发挥直接内存访问(DMA)的效能,关键不是“配对”两个独立功能,而是让 Nginx 的数据路径与内核、硬件协同工作,使数据从磁盘经 DMA 直达网卡,全程绕过 CPU 拷贝和用户空间。这需要配置、系统支持与规避退化行为三者齐备。
必须开启并确认 sendfile 路径生效
基础配置很简单,但仅写这一行远远不够:
-
sendfile on;—— 必须显式开启(虽然新版 Nginx 默认为 on,仍建议明确写出) - 确保它作用于静态资源 location,例如:
location ~* \.(js|css|png|jpg|gif|ico|woff2?)$ {<br> sendfile on;<br> # 其他配套项...<br>} - 用
strace -p $(pgrep nginx) -e trace=sendfile实时验证:高并发请求下是否持续触发sendfile()系统调用;若大量出现read/write,说明已退化
关闭所有破坏零拷贝的运行时处理
gzip、etag、Range 等特性会强制数据进入用户态,彻底绕过 sendfile 路径:
-
禁用运行时压缩:
gzip off;(不是gzip_disable,是全局关) - 改用预压缩:
gzip_static on;+ 提前生成style.css.gz等文件,Nginx 可直接 sendfile 返回 .gz 文件 - 避免动态响应头干扰:
etag off;、expires off;(若需缓存控制,改用add_header Cache-Control,它不触发用户态介入) - Range 请求(如视频拖拽)会禁用 sendfile,如需支持,可考虑用
slice模块分片 + sendfile 分段传输,但默认场景建议接受整文件直传
协同内核与网卡:让 DMA 真正跑起来
sendfile 的零拷贝效果高度依赖底层能力,单靠 Nginx 配置无法激活 SG-DMA:
- 确认内核版本 ≥ 2.4(推荐 ≥ 4.18),并检查网卡是否支持 Scatter-Gather DMA:
ethtool -i eth0 | grep -i dma或查看驱动文档(如 ixgbe、i40e、mlx5 等主流驱动均支持) - 增大 TCP 发送缓冲区,防止 socket 队列满导致 sendfile 阻塞:
net.core.wmem_max = 1048576(1MB),配合net.ipv4.tcp_wmem = 4096 65536 1048576 - 启用
tcp_nopush on;:让 sendfile 输出的数据攒够一个 MTU(约 1460 字节)再发,减少小包数量,提升 DMA 利用率 - 大文件分发时加限制防阻塞:
sendfile_max_chunk 1m;(避免单次 sendfile 占用 worker 过久)
配套缓存与文件系统优化
减少用户态介入频率,维持 sendfile 路径稳定:
-
open_file_cache max=10000 inactive=60s;—— 缓存文件句柄和元数据,避免每次请求都open()/stat() - 静态文件务必放在本地 ext4/xfs 文件系统上;NFS/CIFS 不支持 sendfile,会自动降级
- 避免使用
O_DIRECT打开文件(Nginx 不控制 open 标志),否则绕过页缓存,sendfile 将失效


















