directio核心目标不是提速,而是稳控内存、避免页缓存污染;必须在单次下载致cached激增、kswapd飙升、await抖动、oom频发时启用,并严格满足文件系统支持、内存/偏移/长度对齐及sendfile off等协同配置。

用 directio 优化大文件读取,核心目标不是“提速”,而是避免把几 GB 的视频、镜像或归档文件硬塞进页缓存,防止挤占其他服务内存、触发频繁换页和内核回收抖动。它通过绕过 page cache,让数据从磁盘直通应用缓冲区,从而免除缓存污染。
什么情况下必须考虑 directio
当出现以下现象时,页缓存污染已成实际瓶颈:
- 单次下载一个 4GB 视频,
/proc/meminfo中Cached瞬间涨数 GB,随后kswapdCPU 占用飙升 - 多并发下载时,
iostat -x 1显示await波动剧烈、%util高但吞吐上不去 -
perf record -e 'kmem:*捕获到大量__page_cache_alloc和shrink_inactive_list调用 - 系统剩余内存充足,但应用频繁报
ENOMEM或 OOM Killer 启动——实为 page cache 占满可回收内存
关键配置与对齐要求
directio 不是开关,而是一套协同生效的约束组合。缺一不可,否则静默退回到普通读取:
- 文件系统需支持且挂载合理:ext4 推荐
data=writeback或dioread_nolock;XFS 更稳定,默认适配 - 内存缓冲区必须对齐:用
posix_memalign(&buf, 4096, size)分配,禁用malloc或new - 文件偏移与读取长度必须是逻辑块大小整数倍:查
stat -f /path | grep "I/O Block",按其值对齐(通常 4096) - Nginx 场景下,必须配套:
sendfile off;、gzip off;、add_header Content-Length $sent_http_content_length;、aio on;
如何验证是否真正绕过了页缓存
不能只看配置写了没,要观测真实行为:
- 监控
/proc/meminfo:启用后Cached增长应明显趋缓,尤其在连续读取多个大文件时 - 用
iostat -x 1对比:directio 下await应低于 buffered IO,说明跳过了内核调度排队环节 - 运行
perf stat -e 'syscalls:sys_enter_pread64,block:block_rq_issue' ./your_app:确认block_rq_issue计数显著上升,且无 fallback 到sys_enter_read - 检查
/proc/<pid>/maps</pid>:若未见大段anon内存增长,说明未加载进 page cache
慎用场景与替代方案
directio 不是万能解药,误用反而降低效率:
- 禁止用于小文件混合服务:如同时分发 KB 级 JS 和 GB 级 MP4,应精确用
location ^~ /video/隔离路径 - 不适用于随机读取或频繁 seek:视频编辑预览、数据库索引扫描等场景,保留 page cache +
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)更合适 - 若无法满足对齐或文件系统限制,可用
posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE)减少缓存复用,或设vm.vfs_cache_pressure=200加速 dentry/inode 回收











