如何排查Redis缓存击穿带来的内存溢出风险?

作者:袖梨 2026-08-31

缓存击穿本身不会直接导致内存溢出,它主要压垮数据库;但若兜底逻辑缺陷(如空值缓存未设TTL、fallback反复写入无效key),则可能引发Redis内存泄漏甚至OOM。

缓存击穿本身不会直接导致内存溢出

缓存击穿是热点 key 过期后并发请求穿透到 DB,它主要压垮的是下游数据库,不是 Redis 内存。但如果你的应对逻辑有缺陷——比如用空值或默认对象填充缓存、又没设 TTL,或者 fallback 逻辑反复写入无效 key——那确实会把击穿演变成内存泄漏甚至 OOM。

检查是否因击穿兜底逻辑污染了 Redis

重点排查那些本不该长期存在的 key:空结果缓存、占位符、错误响应体等。这类 key 往往特征明显——数量多、生命周期长、value 很小但总量惊人。

  1. redis-cli --bigkeys 看有没有大量 string 类型的小 key(比如几十字节但上百万个)
  2. 抽样检查疑似兜底 key:redis-cli ttl "cache:order:123456",如果返回 -1(永不过期)或远超业务合理范围(如 7 天以上),就是风险信号
  3. 查 key 命名规律:redis-cli keys "cache:*:fallback*"redis-cli keys "*empty*",确认是否批量生成
  4. 对比 key 数量和业务 QPS:如果 key 总数每天增长 50 万,而订单查询 QPS 只有 200,基本能断定兜底逻辑失控

验证淘汰策略是否对兜底 key 生效

即使你配置了 allkeys-lru,如果这些兜底 key 是刚写入就立刻被访问(比如每次击穿都查一次 fallback),它们会被频繁 touch,实际很难被淘汰。更糟的是,如果用了 noevictionvolatile-* 且没设过期时间,它们就彻底“钉”在内存里了。

  1. 执行 redis-cli config get maxmemory-policy,确认不是 noeviction
  2. 对兜底 key 主动加 TTL:redis-cli expire "cache:user:9999:empty" 300(5 分钟足够缓冲)
  3. 避免在代码里用 SET key value 而不用 SETEXEXPIRE —— 这是最常见的漏设 TTL 场景

监控击穿发生时的内存行为变化

单纯看 used_memory 上涨不说明问题,要结合时间点对齐日志。真正的线索藏在突增的 key 数量和低效的淘汰率里。

  1. 在应用层记录击穿事件(例如捕获 CacheMissException),和 Redis 的 INFO memory 输出做时间对齐
  2. 观察 evicted_keys 指标是否同步上升:如果击穿期间 evicted_keys 几乎为 0,说明淘汰策略失效或 key 根本没被选中
  3. redis-cli --stat 持续观察,击穿高峰若伴随 keyspace_hits 骤降 + keyspace_misses 暴涨 + used_memory 缓慢爬升,大概率是兜底 key 在堆积

真正危险的从来不是击穿那一刻,而是后续几分钟里,几十万条 "cache:xxx:empty" 被无 TTL 地塞进 Redis —— 它们不占多少单个内存,但合起来能吃掉几 GB。别只盯着热点 key 本身,盯住你写的那行 cache.set(key, emptyObj)

相关文章

精彩推荐