sendfile 本身不直接依赖大页内存,但结合标准大页(explicit huge pages)、tcp_nopush、内核≥4.18及sg-dma网卡等协同配置,可减少tlb miss、稳定内核内存路径,显著提升海量并发下零拷贝吞吐性能。

sendfile 本身不直接依赖大页内存(Huge Pages),但结合合理的大页配置,可间接强化其在海量并发下的吞吐表现——关键在于减少 TLB miss、稳定内核内存路径,并配合 sendfile 的零拷贝机制形成协同增益。实际优化需分层推进,不能仅靠开启一个参数。
确认 sendfile 已正确启用并处于零拷贝路径
这是前提,否则大页再好也无从发力:
-
必须显式配置:
sendfile on;(Nginx ≥ 1.3.0 默认支持,但需写明) - 禁用与 sendfile 冲突的模块:关闭
gzip on(改用gzip_static on预压缩)、避免sub_filter或动态add_header出现在静态资源 location 中 - 验证是否真走零拷贝:用
strace -p $(pgrep nginx -f worker) -e trace=sendfile观察调用频次;若同时高频出现read+write,说明已退化
启用并绑定大页内存(Transparent Huge Pages 需谨慎)
Linux 内核通过大页降低页表遍历开销,对频繁访问内核缓冲区(如 sendfile 使用的 page cache 和 socket send queue)有帮助:
-
推荐使用标准大页(Explicit Huge Pages):
• 启动前分配:例如echo 2048 > /proc/sys/vm/nr_hugepages(分配 2GB,按 1MB/页)
• Nginx worker 进程需以mlock()锁定内存(需cap_sys_admin权限或 root),并在启动时加-g "worker_rlimit_memlock 2097152;"(单位 KB) -
慎用 Transparent Huge Pages(THP):
• THP 在 madvise 模式下对 Nginx 无效(sendfile 不触发 madvise);
• always 模式可能引发内存碎片和延迟抖动,尤其在高并发短连接场景下,建议设为madvised或直接never
协同调优:让大页真正服务于 sendfile 路径
大页只有落在关键数据路径上才有效,需确保内核缓存与网络栈受益:
-
增大 TCP 发送队列上限:
net.core.wmem_max = 4194304(4MB),防止 sendfile 推送大量数据时因 socket 缓冲区满而阻塞 -
启用
tcp_nopush on:
使 sendfile 输出的数据与响应头合并为整包发送,减少小包数量,降低 TLB 压力 —— 这是大页收益放大的关键一环 -
调整文件缓存亲和性:
open_file_cache max=20000 inactive=60s;+open_file_cache_valid 60s;,减少 stat/open 系统调用,避免用户态介入打断零拷贝
硬件与内核层面的必要支撑
sendfile + 大页的组合效果高度依赖底层能力:
-
内核版本 ≥ 4.18:支持
aio threads与 sendfile 异步协同,缓解大文件传输时的 worker 阻塞 -
网卡支持 SG-DMA:执行
ethtool -k eth0 | grep scatter-gather,输出scatter-gather: on才能实现 sendfile 的“免 CPU 拷贝”终极形态 -
关闭 NUMA 平衡干扰(多路服务器):
numactl --cpunodebind=0 --membind=0 nginx启动,避免 page cache 跨节点访问拖慢 DMA 效率











