nginx高效分块发送大静态文件依赖sendfile零拷贝、tcp_nopush与range请求协同:需禁用gzip压缩及干扰模块,确保etag有效,并配合read_ahead与open_file_cache优化。

Nginx 对大静态文件的高效分块发送,核心不是“运行时分块压缩”或“动态切片传输”,而是通过 零拷贝直传(sendfile)+ TCP 报文合并(tcp_nopush)+ Range 请求支持 三者协同,在不增加 CPU 开销的前提下,实现低延迟、高吞吐、可断点续传的交付。
sendfile 是基础,但必须守住零拷贝路径
Nginx 默认启用 sendfile on;,但这只是起点。真正生效需满足:
- 同时开启
tcp_nopush on;和tcp_nodelay off;—— 前者攒满 TCP 包再发,后者避免 Nagle 算法干扰; - 文件不能被 gzip 动态压缩(会退化为
read()+write()四次拷贝); - 避免
add_before_body、sub_filter、proxy_pass混用在同一 location; - 文件不能放在 NFS/CIFS 等不支持
sendfile()的挂载点上; - 不要使用
expires epoch;这类需运行时计算的头,否则 ETag/Last-Modified 可能失效,导致 Range 请求被拒绝。
Range 请求天然支持“逻辑分块”,无需额外配置
浏览器拖拽视频、暂停续传、分段加载,都依赖 HTTP Range: bytes=0-1048575 请求。Nginx 原生支持:
- 自动识别
Range头,返回206 Partial Content; - 响应中带
Content-Range和Accept-Ranges: bytes; - 无需开启 slice 模块——这是针对回源场景的优化,本地文件服务直接走内核
sendfile()+splice()即可完成字节范围读取与发送; - 只需确保
etag on;(默认)、if_modified_since on;(默认)未被禁用,否则部分 Range 请求可能降级为 200。
大于 4MB 的文件建议加 read_ahead 1m;
该指令提示内核预加载文件页到 page cache,对 SSD 尤其有效:
- 写在
location块中,如location /video/ { root /data; read_ahead 1m; }; - 不影响小文件,只对大文件生效;
- 配合
open_file_cache使用效果更佳,减少重复open()和stat()系统调用。
日志与缓存要精简,避免拖慢发送链路
- 在纯静态 location 中彻底关闭访问日志:
access_log off;; - 若需记录,禁用
$body_bytes_sent字段(需等响应结束才能获取,阻塞 sendfile 流程); - 启用文件句柄缓存:
open_file_cache max=10000 inactive=60s; open_file_cache_valid 60s; open_file_cache_min_uses 2;
不复杂但容易忽略











