Skip to main content
☘️ Septvean's Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Redis 缓存三大问题

内容:概念、原因、解决方案、实战建议。

Redis 缓存三大问题:

缓存穿透、缓存击穿、缓存雪崩

一、缓存穿透(Cache Penetration)

✅ 是什么?

请求的数据在缓存和数据库中都不存在,每次请求都会直接打到数据库。

🔥 典型场景

  • 请求 不存在的 ID
  • 被恶意攻击(大量随机 key)
  • 接口未做参数校验
GET user:99999999

-> Redis 没有
-> MySQL 也没有
-> 每次都查 DB

❌ 危害

  • DB 被持续打爆
  • 缓存形同虚设

✅ 解决方案(必考)

1️⃣ 缓存空值(最常用)

key 不存在 -> 缓存一个空对象/null
TTL 设置短一点(如 30~60s)
  • ✅ 优点:简单有效
  • ⚠️ 注意:必须设置过期时间

2️⃣ Bloom Filter(布隆过滤器)

  • 请求前先判断 key 是否可能存在
  • 不存在 -> 直接拒绝,不查缓存/DB

📌 适合:

  • 海量 key
  • 恶意攻击场景

3️⃣ 参数校验(最基本)

  • ID <= 0 直接返回
  • 非法参数拦截

☘️ 总结

缓存穿透是访问不存在数据导致 DB 压力,解决方案是缓存空值或使用 Bloom Filter(布隆过滤器)。

二、缓存击穿(Cache Breakdown)

✅ 是什么?

某一个热点 key 过期瞬间,大量并发请求同时打到数据库。

🔥 典型场景

  • 热点商品
  • 热点配置
  • 热点活动
某一秒:
key 过期
10000 个请求同时访问
-> DB 被瞬间击穿

❌ 危害

  • 数据库瞬时压力暴涨
  • 服务 RT 飙升

✅ 解决方案(核心)

1️⃣ 互斥锁(最经典)

第一个请求:
  加锁 -> 查 DB -> 回填缓存
其他请求:
  等锁 / 返回旧值

📌 实现方式:

  • Redis SETNX
  • Redisson 分布式锁

2️⃣ 逻辑过期(高级)

value = {
  data: xxx,
  expireTime: 2025-01-01 12:00:00
}
  • 过期了也先返回旧值
  • 后台异步更新缓存

📌 适合:

  • 读多写少
  • 允许短时间脏数据

3️⃣ 热点 key 永不过期(简单粗暴)

  • 只人工或定时刷新

☘️ 总结

缓存击穿是热点 key 失效导致并发打 DB,解决方案是互斥锁或逻辑过期。

三、缓存雪崩(Cache Avalanche)

✅ 是什么?

大量 key 在同一时间过期或 Redis 整体不可用,导致所有请求涌向数据库。

🔥 典型场景

  • 大量 key 使用相同 TTL
  • Redis 宕机
  • Redis 重启、主从切换

❌ 危害(最严重)

  • DB 被打死
  • 整个系统雪崩式故障

✅ 解决方案(必背)

1️⃣ 过期时间加随机值(最常用)

TTL = 300 + random(0~60)

避免大量 key 同时过期。

2️⃣ 多级缓存

本地缓存 -> Redis -> DB

Redis 挂了仍有兜底。

3️⃣ Redis 高可用

  • 主从复制
  • Sentinel
  • Cluster

4️⃣ 限流 + 熔断(系统级)

  • QPS 限制
  • 降级返回默认值

☘️ 总结

缓存雪崩是大量缓存失效或 Redis 不可用导致 DB 被压垮,解决方案是 TTL 随机化和高可用架构。

🔥 三大问题对比

问题 核心原因 影响范围 解决重点
缓存穿透 数据不存在 持续 空值缓存 / Bloom
缓存击穿 热点 key 过期 瞬时 锁 / 逻辑过期
缓存雪崩 大量 key 同时失效 全局 随机 TTL / 高可用

🎯 其它

Q:这三者最大区别?

👉 是否存在、是否热点、是否大面积。

Q:最容易被忽略的是哪个?

👉 缓存击穿(热点 key)。

Q:生产环境最推荐方案?

  • 穿透:缓存空值 + Bloom
  • 击穿:互斥锁
  • 雪崩:TTL 随机 + Redis 高可用

通过计划任务,定期更新缓存,能不能解决 Redis 缓存三大问题?

结论:

仅靠“计划任务定期更新缓存”,不能彻底解决 Redis 缓存三大问题,只能缓解其中一部分。

下面按 穿透 / 击穿 / 雪崩,逐一给出可落地的结论。

总览(先记住):

问题 定期任务能否解决 结论
缓存穿透 ❌ 不能 数据本就不存在
缓存击穿 ⚠️ 部分缓解 热点 key 仍有风险
缓存雪崩 ⚠️ 只能缓解一类 无法应对 Redis 不可用

一、缓存穿透 ❌ —— 完全解决不了

回顾定义:

请求的数据在缓存和数据库中都不存在

定期任务的问题在哪?

  • 定时任务 只会更新“存在的数据”
  • 不存在的数据 根本不知道要更新什么

例子

GET user:99999999  (DB 根本没有)

即使你每 5 分钟全量刷新缓存:

  • 这个 key 依然不存在
  • 请求仍然每次打到 DB

✅ 正确解法

  • 缓存空值
  • Bloom Filter(布隆过滤器)
  • 参数校验

🎯 结论

缓存穿透是“访问不存在数据”的问题,定期更新缓存无法感知不存在的数据,因此无效。

二、缓存击穿 ⚠️ —— 只能缓解,不能根治

回顾定义:

热点 key 失效瞬间,大量并发请求打 DB

定期任务能做什么?

  • 在 key 过期前刷新缓存
  • 理论上让热点 key 不过期

✅ 在理想情况下有效

❌ 实际生产中的问题

1️⃣ 定时任务可能失败

  • 任务执行失败
  • 数据库抖动
  • 网络问题

👉 一旦刷新失败,热点 key 仍然会过期。

2️⃣ 定时任务不是实时的

  • 刷新周期是 1 分钟 / 5 分钟
  • 在周期空档仍可能过期

3️⃣ 多实例并发刷新

  • 多个节点同时刷新
  • DB 压力集中

✅ 正确姿势(组合拳)

定期任务 + 互斥锁 / 逻辑过期
  • 定期任务:减少击穿概率
  • 锁 / 逻辑过期:兜底防并发

🎯 结论

定期更新缓存只能降低热点 key 失效概率,不能替代互斥锁或逻辑过期机制。

三、缓存雪崩 ⚠️ —— 只能解决“同时过期”,解决不了“不可用”

雪崩的两种来源

1️⃣ 大量 key 同时过期

2️⃣ Redis 整体不可用

定期任务能解决哪一种?

✅ 能缓解:大量 key 同时过期

  • 定时任务错峰刷新
  • 减少同一时间失效的 key 数量

❌ 完全无能为力:Redis 宕机

  • Redis crash
  • 主从切换
  • 网络隔离

此时:

所有请求 -> DB

不管你有没有定时任务。

✅ 正确方案

  • TTL 随机化
  • Redis 主从 / Sentinel / Cluster
  • 本地缓存
  • 限流 & 熔断

🎯 结论

定期更新缓存只能缓解“过期型雪崩”,无法应对 Redis 不可用导致的雪崩。

🔥 总结

通过计划任务定期更新缓存,只能作为辅助方案,不能解决 Redis 缓存三大问题。

  • 对缓存穿透无效,因为数据本身不存在;
  • 对缓存击穿只能降低热点 key 失效概率,仍需互斥锁或逻辑过期兜底;
  • 对缓存雪崩只能缓解大量 key 同时过期,无法应对 Redis 不可用。

因此生产环境必须结合空值缓存、Bloom Filter(布隆过滤器)、锁机制和高可用架构一起使用。

☘️ 架构级最佳实践总结

定期任务(降概率)
+ 逻辑过期(防击穿)
+ 空值缓存 / Bloom(防穿透)
+ TTL 随机(防雪崩)
+ Redis 高可用(兜底)

Bloom Filter(布隆过滤器)

参考文档:

布隆过滤器(Bloom Filter)是1970年被布隆提出来的,用于判断某个元素是否在一个集合中,优点是空间效率和查询时间都非常高,缺点是有一定的误判率和删除困难。

布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,由一个超长的二进制位数组和多个哈希函数组成。

它主要用于快速判断元素是否存在于海量数据集合中,特点是能保证“绝对不存在”,但判断“存在”时存在一定误判率(假阳性)。

核心原理

  • 初始化:创建一个全为 0 的超长二进制数组。
  • 添加元素:使用多个独立的哈希函数对元素进行计算,将得到的多个位置的比特位由 0 置为 1。
  • 查询元素:再次使用相同的哈希函数计算出位置,若对应位置全为 1,则认为元素可能存在;若有任何一位为 0,则该元素一定不存在。

特点与权衡

优点:

  • 空间效率高:不存储具体元素内容,仅存储比特位,节省内存。
  • 查询速度快:时间复杂度为 (O(k)),其中 (k) 为哈希函数个数。

缺点:

  • 存在误判(假阳性):可能会将不存在的元素误判为存在(因为哈希碰撞),但不会出现假阴性(判断不存在则一定不存在)。
  • 难以删除:通常不支持直接删除元素,因为多个元素可能共享相同的位。

主要应用场景

  • 防止缓存穿透:在查询数据库前先通过布隆过滤器过滤掉非法请求。
  • 海量数据去重:如爬虫过滤已爬取的 URL、垃圾邮件过滤。
  • 大数据量判断:检查元素是否存在于庞大的集合中,如 Hbase 和 BigTable 中的行键查询加速。