核心是让nginx少查磁盘、少进用户态、少做拷贝:open_file_cache缓存元数据减少stat/open开销,sendfile实现内核零拷贝直传page cache,二者协同需满足文件本地真实存在、禁用gzip等改写模块、配合tcp_nopush填满tcp包。

在高吞吐静态文件下载场景下,open_file_cache 与 sendfile 的协同调优,核心是让 Nginx 少查磁盘、少进用户态、少做拷贝——三者叠加才能释放最大 I/O 效率。
确保 sendfile 真正生效的硬性前提
sendfile 不是“开了就快”,它只在严格满足以下条件时走零拷贝路径:
- 请求必须命中真实磁盘文件(
root或alias指向本地路径),不能经过proxy_pass、fastcgi_pass或任何内容改写指令 - 响应头和响应体不能被动态修改:禁用
gzip on、sub_filter、etag on、expires等模块(纯静态服务建议全局关掉) - 文件系统需支持 mmap(ext4/xfs 默认支持;NFSv4 可用,但 NFSv3 或挂载含
noac时易阻塞) - 内核需启用
CONFIG_SOCK_SENDPAGE(主流发行版默认开启,可忽略)
open_file_cache 缓存元数据,减少 stat 和 open 开销
高频小文件下载(如图标、字体、JS/CSS)下,反复 stat() 和 open() 会成为瓶颈。配置示例:
-
open_file_cache max=20000 inactive=60s;—— 最多缓存 2 万个 fd,60 秒未访问即淘汰 -
open_file_cache_valid 60s;—— 每 60 秒主动检查一次缓存项是否仍有效(避免文件被删后仍返回 200) -
open_file_cache_min_uses 3;—— 同一文件至少被访问 3 次才进缓存,防冷文件污染 -
open_file_cache_errors on;—— 把ENOENT、EACCES等错误也缓存,避免反复报错
搭配 sendfile on 后,Nginx 能直接从缓存中拿到有效 fd 和文件大小/修改时间,跳过所有系统调用,直奔 page cache 读取。
tcp_nopush + sendfile 协同,填满 TCP 报文段
sendfile 解决“怎么发”,tcp_nopush 解决“什么时候发”:
-
tcp_nopush on;让内核攒够一个 MTU(通常 1460 字节)再发,把 HTTP 响应头 + 文件内容一次性推入发送队列 - 这对大文件分块传输尤其关键:避免每段几 KB 就发一个小包,大幅降低 ACK 往返和网络开销
- 注意冲突:
tcp_nodelay on会关闭 Nagle 算法,与 tcp_nopush 对立;大文件下载场景应设为tcp_nodelay off
大文件(≥4MB)需额外规避 page cache 污染
单个大文件反复读取会挤占 page cache,导致小文件缓存被踢出。此时应绕过内存缓存,直读磁盘:
-
directio 4m;—— 文件 ≥4MB 时启用 direct I/O,跳过 page cache -
aio on;—— 配合 directio,启用内核异步 I/O,避免阻塞 worker 进程 -
output_buffers 1 128k;—— 控制输出缓冲区大小,适配 directio 场景 -
sendfile_max_chunk 0;—— 防止旧内核对超大文件做无效分段(如 >1GB 视频)
该组合让小文件靠缓存+零拷贝飞速响应,大文件靠异步直读稳定输出,互不干扰。











