keys_zone内存溢出导致缓存索引失效,表现为X-Cache-Status恒为MISS、$upstream_cache_status大量为空或MIS、磁盘有文件但无法命中;需检查error.log报错、keys_zone大小与key数量匹配度,并优化cache_key、扩容zone或调整loader参数。

proxy_cache 内存共享区(keys_zone)溢出不会直接报错“缓存失效”,而是让 Nginx 无法注册新缓存项、key 查找失败、命中率骤降甚至拒绝缓存写入——表面看是缓存不生效,实则是索引内存已满,缓存系统“失明”。
确认 keys_zone 是否真的耗尽
shared memory zone 存储的是所有缓存项的元信息(key 的 hash 值、过期时间、文件路径等),不存实际响应体。它满了,Nginx 就无法记录新缓存,旧缓存也无法被正确查找。
- 查 error.log 中是否有 "cache miss due to no memory in shared zone" 或类似提示(部分版本会输出 "no memory in cache"、"cache manager failed to allocate")
- 用 nginx -T | grep proxy_cache_path 确认当前生效的 keys_zone 大小,例如 keys_zone=my_cache:10m
- 估算 key 数量:每个缓存 key 元信息约占用 512B–1KB。若你有 50 万个活跃 key,至少需 256MB;100 万则需 500MB+。10m 区域在中高并发下极易撑满
- 检查是否启用了 loader 配置(如 loader_files 200),启动时大量加载旧缓存元数据可能瞬间冲爆 zone
观察缓存行为异常信号
内存区满不是静默失败,会有可验证的副作用:
- X-Cache-Status 恒为 MISS,即使同一请求反复发,也从不出现 HIT 或 EXPIRED —— 因为 key 根本没进内存索引
- access_log 中 $upstream_cache_status 字段大量显示 -(空值)或 MIS,极少或没有 HIT/STALE/EXPIRED
- 缓存目录(如 /var/cache/nginx/my_cache/)下有大量文件,但 ls -l | wc -l 显示文件数远超预期,说明磁盘有内容,但内存索引丢失,Nginx 找不到它们
- 重启 Nginx 后首次请求变快(因 loader 未全加载),随后性能逐步下降,伴随 worker 进程 RSS 内存缓慢上涨 —— 是 zone 持续碎片化或填满的典型表现
快速验证与调优方法
不要只加内存,先确认是否真由 key 膨胀引发:
- 临时缩小缓存范围:在 location 中加 proxy_cache_valid 200 1s; + proxy_cache_min_uses 10;,大幅降低新 key 注册频率,观察 MISS 是否减少
- 精简 cache_key:改用 proxy_cache_key "$host$uri";,坚决剔除 $args、$cookie_*、$http_user_agent 等高基数变量
- 扩容 keys_zone:将 keys_zone=my_cache:10m 改为 keys_zone=my_cache:256m(注意单位是 m,不是 MB),并配合 inactive=1h 加速过期 key 清理
- 启用 loader 控制:添加 loader_threshold 200ms; loader_files 100; loader_sleep 50ms;,避免 Nginx 启动时一次性加载全部元数据压垮 zone
避免误判的干扰项
有些现象看似像内存溢出,实为其他配置掩盖了真实问题:
- 如果 proxy_cache_path 目录权限不对(如属主非 nginx 用户),Nginx 写缓存文件失败,error.log 会出现 (13: Permission denied),此时也会表现为无 HIT,但和内存无关
- 若配置了 proxy_cache_lock on; 且 proxy_cache_lock_timeout 过短(如 50ms),高并发下大量请求锁失败后可能直接回源,造成“看起来没缓存”,实为锁机制拦截
- 使用了 if 块内设置 proxy_cache_bypass 等指令,会导致配置非法,Nginx 可能静默跳过整段缓存逻辑











