levels参数不加快单次查找,但能显著缓解高并发下因目录文件过多导致的I/O瓶颈;其核心是通过哈希分层使文件均匀分散,避免单目录堆积数千缓存文件。

直接说结论:levels 参数不加快单次查找,但能显著缓解高并发下因目录文件过多导致的 I/O 瓶颈。核心是让文件均匀分散,避免单目录堆积成千上万个缓存文件。
为什么 levels=0 会拖慢整体性能
当不设 levels(即 levels=0)时,所有缓存文件都落在同一个目录里。一旦缓存条目超过 10 万,ext4 或 xfs 文件系统在做 stat、open 等操作时,目录项线性扫描或哈希桶冲突就会明显增加延迟。这不是 Nginx 慢,而是底层文件系统扛不住。
- ext4 默认用 linear search 查找目录项,文件越多越慢
- xfs 的 dir2 结构在单目录超数万文件后,目录块分裂和查找开销上升
- Nginx 每次缓存命中都要访问文件元数据,高频小文件 I/O 下瓶颈立刻暴露
levels=1:2 是当前最实用的分层方案
它把缓存路径按 MD5 哈希值前几位拆成两级子目录:第一级 16 个(0–f),第二级每个再分 256 个(00–ff),总共 4096 个叶子目录。这样即使有百万级缓存条目,每个目录平均只有几百个文件,目录查找基本保持常数时间。
- 路径示例:
/var/cache/nginx/mycache/a/1b/a1b2c3...(MD5 值前三位决定路径) - 固定映射带来局部性优势:相同请求总落同一目录,利于 page cache 复用和磁盘预读
- 比 levels=2:2(65536 目录)更轻量,管理成本低,实际场景中已足够均衡
配合其他参数才能真正发挥效果
只设 levels 不够,必须同步控制内存索引容量、缓存生命周期和文件系统行为:
- keys_zone 至少配 10m:1m 约存 8000 个 key,10m 可支撑约 8 万个活跃缓存项,避免 key 冲突淘汰
- inactive 时间别设太短:如仅 60s,会导致频繁清理和重建,加剧 I/O;建议按业务热度设为 30m–2h
- use_temp_path=off:让临时文件直接写入缓存目录,避免跨文件系统 copy,减少一次磁盘写
-
挂载选项优化:SSD 上推荐
noatime,nobarrier(xfs)或noatime,commit=60(ext4),降低元数据更新开销
缓存 key 设计影响目录分布均衡度
路径由 cache_key 经 MD5 后取前几位生成,如果 key 中含时间戳、随机串或用户 ID,会导致哈希散列严重不均——有些目录爆满,有些长期空置。结果仍是局部 I/O 压力集中。
- 推荐 key 构造:去掉动态参数,保留稳定部分,例如
$scheme$host$request_uri - 避免使用
$request_time、$cookie_sessionid这类高熵字段 - 可通过日志统计各子目录文件数(如
find /var/cache/nginx/mycache -type d -name "[0-9a-f]" | xargs -I{} sh -c 'echo {} $(ls {} | wc -l)')验证是否均衡











