优化Nginx sendfile与异步传输需分层调度:热数据启用sendfile on+tcp_nopush on并禁用gzip/etag等干扰项;冷大文件(≥4MB)配置directio 4m;+aio on;隔离I/O;辅以thread_pool和open_file_cache降低元数据与日志I/O干扰。

优化 Nginx 的 sendfile 与异步传输,关键在于让热数据走零拷贝路径、冷大文件绕开 page cache,并避免二者互相干扰。不是简单“都打开”,而是按文件特征分层调度,减少内核 I/O 队列争抢和内存污染。
确保 sendfile 零拷贝真正生效
sendfile 不是开了就一定走零拷贝——它极易被其他配置悄悄禁用:
- 必须显式启用:
sendfile on;(默认是 off) - 搭配
tcp_nopush on;,让 sendfile 发出的数据尽量填满 TCP 包,减少小包重传和协议栈开销 - 关闭所有会触发响应体/头修改的功能:包括
gzip off;、etag off;、expires off;、sub_filter off;;这些一旦开启,Nginx 必须把文件读进用户态处理,sendfile 自动退化为 read+write 模式 - 避免在 location 中混用
alias+ 正则路径,某些匹配逻辑会导致内部重定向,破坏零拷贝链路;优先用root+ 精确前缀(如^~ /static/)
对大文件启用 directio + aio,隔离 I/O 路径
4MB 以上的视频、安装包等大文件若走 sendfile,会大量占用 page cache,挤占小文件缓存空间,反而拖慢整体响应。应让它们绕过内存,直读磁盘:
- 在对应 location 块中配置:
directio 4m;(表示 ≥4MB 文件启用直接 I/O) - 同时启用异步读:
aio on;(Linux 内核 2.6.22+ 支持) - 补充缓冲设置:
output_buffers 1 128k;,减少 sendfile 回退时的临时缓冲压力 - 注意互斥关系:directio 和 sendfile 不能共存于同一请求路径——Nginx 检测到 directio 后会自动禁用 sendfile,所以无需手动关,但也不能在同一 location 下强行保留 sendfile
用线程池分担阻塞型 I/O 压力
即使启用了 aio,部分场景(如 NFS 存储、慢盘、高并发 stat())仍可能引发 worker 进程短暂阻塞。引入线程池可把磁盘 I/O 操作移交后台线程处理:
- 在 main 块定义线程池:
thread_pool default threads=32 max_queue=65536; - 在 location 中启用:
aio threads=default; - 该配置对大文件下载、日志写入、SSL 握手等耗时操作同样有效,能显著降低 worker 进程因等待 I/O 而空转的概率
减少元数据访问和日志 I/O 干扰
高频小文件请求下,反复 stat() 判断文件是否存在、是否可读,本身就会成为 I/O 瓶颈:
- 启用文件句柄与元数据缓存:
open_file_cache max=20000 inactive=30s; - 配合:
open_file_cache_valid 60s;和open_file_cache_min_uses 2;,避免刚缓存就淘汰 - 纯静态服务节点建议彻底关闭访问日志:
access_log off;;若需记录,改用 syslog 或压缩日志,避免本地磁盘写入竞争











