排查Nginx缓存I/O卡顿需聚焦“缓存落盘方式、元数据查找效率、写入触发源”:先用iostat/iotop定位是否nginx worker真在写cache路径,再查levels目录结构、use_temp_path=off配置及temp与cache是否同盘,最后验证设备队列、调度器和挂载参数是否匹配硬件能力。

排查 Nginx 缓存文件因磁盘 I/O 过高引发的性能卡顿,关键不是看“有没有缓存”,而是看“缓存怎么落盘”“元数据怎么查”“谁在反复触发写入”。很多卡顿表面是缓存慢,实则是目录结构不合理、临时路径拷贝冗余、或元数据频繁 stat 导致的系统调用风暴。
确认是否真是 fastcgi_cache 引发 I/O 高峰
先排除干扰项:error_log 不支持缓冲,若设为 debug 级别,会持续小块同步写;client_body_in_file_only on 或 proxy_buffering off 也会绕过内存缓存直写磁盘。这些都比 fastcgi_cache 更容易成为 I/O 源。
- 用 iostat -x 1 观察日志盘(如 /dev/sda)的 %util 和 await,同时记录高 I/O 时间段
- 用 iotop -oP -d 1 查看此时实际写盘的进程是否为 nginx worker,再用 lsof -p [PID] 确认其写入目标是否为 fastcgi_cache_path 下的文件
- 检查 access_log 是否也启用了 buffer=64k flush=1s —— 若没开,高频小写可能掩盖了缓存本身的 I/O 特征
检查缓存路径结构与元数据压力
单目录下缓存文件超万,ext4/xfs 的 inode 查找会明显变慢,表现为大量 D 状态进程和高 avgqu-sz,但 iotop 却看不到明显写入——这是元数据瓶颈,不是内容写入瓶颈。
- 执行 find /path/to/fastcgi_cache -type f | wc -l 统计总文件数;再随机选几个子目录(如 a/ab/)看是否已散列分布
- 确认配置中是否显式写了 levels=1:2;若缺失,Nginx 默认不建多级目录,所有缓存挤在根目录
- 用 strace -p $(pgrep nginx) -e trace=openat,stat,fstat 抓取系统调用,若看到大量重复 stat() 调用,说明 open_file_cache 未启用或 inactive 时间太短
验证缓存写入行为是否合理
默认情况下,Nginx 先写 fastcgi_temp_path,再 rename 到 cache 目录——这带来两次磁盘写 + rename 锁竞争,尤其在高并发时极易堆积。
- 检查 fastcgi_cache_path 行是否包含 use_temp_path=off;该参数必须与路径定义写在同一行,单独配置无效
- 确认 fastcgi_temp_path 和 fastcgi_cache_path 是否在**同一磁盘分区**;若跨盘,rename 会退化为 copy+unlink,I/O 翻倍
- 用 strace -p $(pgrep nginx) -e write,fsync,fdatasync -s 128 观察:开启 use_temp_path=off 后,write() 应直接命中 cache 文件,且无额外 fsync 频繁触发
协同检查磁盘底层承载能力
即使缓存配置最优,若磁盘本身队列深度不足、调度器不匹配或挂载参数加重同步负担,仍会放大 I/O 延迟。
- 运行 cat /sys/block/sda/queue/nr_requests 查设备队列大小,NVMe 建议 ≥512;SSD ≥256;HDD ≥128
- 执行 cat /sys/block/sda/queue/scheduler,SSD/NVMe 应为 none 或 mq-deadline,非 deadline 或 cfq
- 检查挂载参数:mount | grep sda,避免出现 data=journal(ext4)、barrier=1、commit=1 等加重 journal 压力的选项



















