sendfile 在高并发视频下载中需网卡 SG-DMA、内存 page cache 优化与 Nginx 配置协同才能实现零拷贝:确认 ethtool 散列开启、调优 vm 参数、限制 worker 内存锁、location 精确启用并验证 strace/perf 运行时行为。

在高并发视频流下载场景下,sendfile 是降低 CPU 和内存压力的核心机制,但它能否真正发挥效能,高度依赖网卡能力与内存路径的协同优化。单纯开启 sendfile on 并不能自动解决网卡打满或内存缓冲堆积问题——必须从内核、网卡驱动、Nginx 配置三者联动入手。
网卡需支持 SG-DMA 并启用硬件卸载
Linux 2.4+ 内核的 sendfile 要实现“近乎零 CPU 拷贝”,前提是网卡支持 Scatter-Gather DMA(SG-DMA),即允许网卡直接从内核页缓存(page cache)读取分散的数据块,无需 CPU 组包。
- 用
ethtool -k eth0 | grep scatter-gather确认输出为scatter-gather: on;若为 off,需更新驱动或启用对应内核模块(如ixgbe、igb) - 同时开启 TCP 卸载:检查
ethtool -k eth0中tx offload、rx offload、tcp-segmentation-offload是否均为 on;TSO/GSO 可减少协议栈分段开销,配合sendfile提升大包吞吐 - 避免使用虚拟网卡(如 Docker bridge、VMware NAT)直连生产流量——它们通常不透传 SG-DMA 能力,建议改用 macvlan、SR-IOV 或 host 网络模式
内存层面要规避 page cache 拥塞与 swap 干扰
sendfile 依赖内核 page cache 加速磁盘读取,但高并发大文件读取易引发 page cache 压力,表现为 kswapd 活跃、pgpgin/pgpgout 指标飙升,甚至触发 swap。
- 调大
vm.vfs_cache_pressure=50(默认 100),降低 dentry/inode 缓存回收优先级,让 page cache 更稳定 - 限制单个 worker 进程可锁定的内存页:在
nginx.conf的worker_rlimit_core和worker_rlimit_memlock中设合理上限(如worker_rlimit_memlock 2G;),防止 page cache 被其他进程挤占 - 禁用 swappiness:
vm.swappiness=1,避免空闲内存被轻易换出,保障 sendfile 所需的热页常驻
Nginx 配置必须堵住所有退化路径
即使网卡和内存就绪,Nginx 仍可能因配置疏漏退回 read/write 模式,导致 CPU 翻倍、内存拷贝激增。
- 只在视频 location 中启用:
location ~ \.(mp4|webm|mov|mkv)$ { sendfile on; tcp_nopush on; tcp_nodelay off; gzip off; } - 确保响应含
Content-Length:对 NFS/CIFS 存储的视频,需确认其文件系统支持stat()快速获取大小;否则 Nginx 会降级为 chunked,禁用 sendfile - 关闭干扰模块:显式设置
etag off;、expires off;(改用add_header Cache-Control "public, immutable";),避免响应头动态生成介入用户态
验证是否真正在走零拷贝路径
不能只看配置,要观察运行时行为:
- 用
strace -e trace=sendfile -p $(pgrep -f "nginx: worker") -s 128持续抓取,应高频出现sendfile(…)调用,而非read(…)+write(…) - 监控
/proc/net/snmp中TcpOutSegs与TcpOutDataSegs比值:启用tcp_nopush后,后者占比应显著升高(说明数据包有效载荷率提升) - 用
perf top -p $(pgrep nginx) -e syscalls:sys_enter_sendfile查看 sendfile 系统调用耗时占比,若低于 5%,说明路径高效


















