← 返回题目列表

Redis 缓存穿透、击穿和雪崩有什么区别?怎么解决?

高频 中等 第 8 / 36 题 更新于 2026/07/27
Redis缓存穿透缓存击穿缓存雪崩

简化版

缓存穿透是查不存在的数据,请求绕过缓存打到数据库;缓存击穿是热点 key 过期,大量请求瞬间打到数据库;缓存雪崩是大量 key 同时失效或 Redis 故障,导致数据库被流量压垮。对应解决方案是缓存空值/布隆过滤器、互斥锁或逻辑过期、过期时间随机化和多级缓存/限流降级。

详细版

三者区别:

问题典型表现核心原因常见方案
缓存穿透不存在的数据反复查库缓存和数据库都没有缓存空值、布隆过滤器、参数校验
缓存击穿单个热点 key 过期瞬间查库热点 key 失效互斥重建、逻辑过期、热点不过期
缓存雪崩大量请求同时查库大批 key 同时失效或 Redis 不可用TTL 随机、限流降级、多级缓存、高可用

面试回答时要先定义清楚“穿透、击穿、雪崩”的对象范围:穿透是不存在数据,击穿是单个热点 key,雪崩是大面积失效或缓存层不可用。

完整版教学

一、缓存穿透:请求查的是不存在的数据

比如用户不断请求 id=-1 或数据库中不存在的商品 ID。缓存里没有,数据库里也没有,于是每次都绕过缓存打到数据库。

解决方案:

  • 参数校验:明显非法的 ID 直接拦截;
  • 缓存空值:数据库查不到,也把空结果缓存一小段时间;
  • 布隆过滤器:提前判断某个 ID 是否可能存在,不存在就不查库。

缓存空值要设置较短 TTL,避免数据库后来新增数据后长时间查不到。

用数字看,攻击者每秒请求 2 万个随机商品 ID,其中 99% 数据库都不存在。如果每次都查库,数据库会被无意义请求拖垮;缓存空值后,同一个不存在 ID 在短 TTL 内会被 Redis 拦住;布隆过滤器则能在请求进入缓存和数据库前先判断“这个 ID 一定不存在”。穿透治理重点是挡住不存在数据的重复回源。

穿透请求路径:
请求 id=999999999
 -> Redis miss
 -> DB miss
 -> 不做处理:下次同样路径继续打 DB
 -> 缓存空值/布隆过滤器:下次提前拦截

二、缓存击穿:热点 key 过期的一瞬间

击穿针对的是一个或少数热点 key。平时请求都被缓存挡住,突然这个 key 过期,海量请求同时发现缓存没有,于是一起查数据库。

解决方案:

  • 互斥锁重建:只有一个线程查库并回填缓存,其他线程等待或返回旧值;
  • 逻辑过期:缓存值里存过期时间,发现逻辑过期后异步重建,先返回旧数据;
  • 热点 key 不设置物理过期:通过后台任务刷新。

强一致场景要谨慎返回旧值,不能为了抗压牺牲业务正确性。

假设一个热点商品详情平时每秒 1 万次读取,缓存突然过期。如果 1 秒内有 1 万个请求同时查库并重建缓存,数据库会承受原本 Redis 扛住的全部流量。互斥重建的思路是只允许 1 个请求查库,其余请求等待、快速失败或返回旧值;逻辑过期的思路是缓存物理上不删除,发现逻辑过期后异步刷新。

方案优点代价
互斥锁重建数据较新,回源少等待和锁超时处理复杂
逻辑过期高可用,热点不突然消失可能短暂返回旧值
热点不过期避免过期击穿需要后台刷新和兜底

记忆钩子:击穿是“一个热点 key 门突然开了”,治理目标是别让所有请求同时冲到数据库。

三、缓存雪崩:缓存层大面积失效

雪崩通常有两类:

  • 大量 key 设置了相同 TTL,在同一时间集中失效;
  • Redis 故障或网络异常,缓存整体不可用。

解决方案:

  • TTL 加随机值,避免同一时间失效;
  • Redis 做主从、哨兵或集群;
  • 本地缓存做兜底;
  • 限流、熔断、降级保护数据库;
  • 热点数据预热。

雪崩的处理重点是系统保护,而不只是某个 key 的重建。

例如 100 万个商品 key 都设置为整点过期,到了 00:00 大量请求同时 miss,数据库流量会瞬间上升。TTL 随机化可以把 3600s 改成 3600s + random(0,600s),让过期时间分散在 10 分钟窗口内。若 Redis 整体故障,则需要高可用、多级缓存、限流降级来保护数据库,而不是只讨论单个 key 回填。

四、布隆过滤器不是万能的

布隆过滤器可以判断“某个值一定不存在或可能存在”。它有误判率:可能把不存在判断成可能存在,但不会把真实存在判断成一定不存在。

它适合抵挡大量非法 ID 查询,但要考虑数据新增时同步更新布隆过滤器,以及误判导致的少量查库。

布隆过滤器的回答要把“误判方向”说准。它可能把不存在的 ID 判断为可能存在,于是仍会查 Redis 或数据库;但不会把已加入过滤器的真实 ID 判断为一定不存在。新增数据时如果没有及时写入布隆过滤器,可能出现刚创建的数据被挡掉,因此新增链路要同步更新过滤器,或在业务上允许短暂延迟。

BloomFilter 判断:
不存在 -> 一定不存在:直接拦截
可能存在 -> 继续查缓存/数据库

五、工程上要组合拳

真实系统里三类问题可能同时出现。比如大促开始前热点数据没有预热,缓存 TTL 又集中到期,既有击穿也有雪崩风险。

比较稳的组合是:参数校验 + 空值缓存 + 热点 key 保护 + TTL 随机 + 限流降级 + Redis 高可用。

大促前可以提前预热热点商品、给热点 key 使用逻辑过期、给普通 key 设置随机 TTL、对不存在 ID 做布隆过滤器拦截,同时在网关或服务层限流。这样即使某一层失效,后面还有保护。缓存治理不应只靠 Redis 本身,还要结合入口校验、应用本地缓存、数据库保护和监控告警。

六、三者对比时要抓对象范围

面试中最容易混的是击穿和雪崩。击穿是少数热点 key 过期导致大量请求打库;雪崩是大量 key 同时失效或缓存层整体不可用。穿透则完全是另一个维度:查的是不存在数据。先把对象范围说清,再讲方案,答案就稳。

问题对象范围请求是否查到 DB 数据关键词
穿透不存在 keyDB 也没有空值、布隆过滤器
击穿单个热点 keyDB 有互斥重建、逻辑过期
雪崩大量 key 或缓存层DB 可能有大量数据TTL 随机、高可用、限流

七、常见误区与追问

  • 误区:穿透、击穿、雪崩都是缓存过期。 穿透是查不存在数据,击穿是热点 key 过期,雪崩是大面积失效或缓存整体不可用。
  • 误区:缓存空值 TTL 可以设置很长。 空值 TTL 过长会影响后续新增数据可见性,通常要短 TTL 并结合业务更新删除。
  • 误区:布隆过滤器能保证 100% 准确。 布隆过滤器有误判率,只能保证已加入元素不会被判断为一定不存在。
  • 误区:击穿用互斥锁后就没有风险。 锁超时、等待堆积、重建失败都要处理,热点高可用场景常配合逻辑过期。
  • 追问:Redis 整体不可用属于哪类问题? 更接近雪崩,因为大量请求同时绕过缓存打到数据库,需要高可用、限流、降级和本地缓存保护。
  • 追问:热点 key 逻辑过期为什么可能返回旧值? 因为物理缓存仍保留旧数据,发现逻辑过期后异步刷新,刷新完成前可能短暂返回旧值。

八、加强记忆

穿透、击穿、雪崩要按对象范围记:穿透是查不存在数据,缓存和数据库都没有;击穿是单个热点 key 过期,大量请求同时回源;雪崩是大量 key 同时失效或 Redis 整体不可用。穿透靠参数校验、空值缓存、布隆过滤器;击穿靠互斥重建、逻辑过期、热点预热;雪崩靠 TTL 随机、高可用、多级缓存、限流和降级。真正线上要打组合拳,而不是拿一个方案包治三类问题。