Skip to Content
面试题库Redis[面试题] 什么是缓存击穿、缓存穿透、缓存雪崩?

📖 版块 A:知识讲解版 (温故知新)

在高性能架构中,缓存(通常指 Redis)作为数据库(DB)的挡箭牌,能抗住绝大部分并发请求。当这层防护失效时,就会出现以下三种场景:

  1. 缓存穿透 (Cache Penetration)

    • 定义:请求的数据在缓存中没有,在数据库中也没有。由于数据库没查到,自然不会写入缓存,导致每次请求都直接打到数据库。
    • 场景:恶意攻击(如查询 ID 为 -1 的数据)或业务逻辑逻辑漏洞。
    • 方案:接口参数校验、布隆过滤器(Bloom Filter)、缓存空对象(设置短过期时间)。
  2. 缓存击穿 (Cache Breakdown)

    • 定义:一个极其“热点”的 Key,在某个时间点过期了。此时正好有海量并发请求过来,这些请求发现缓存失效,会同时去数据库加载数据并回设缓存,瞬间压垮数据库。
    • 场景:爆款商品秒杀、热搜新闻。
    • 方案:互斥锁(Mutex Lock)、逻辑过期(数据永不过期,但在值里维护一个过期时间字段,发现过期后异步刷新)。
  3. 缓存雪崩 (Cache Avalanche)

    • 定义:在短时间内,大量的缓存 Key 同时失效,或者 Redis 服务器宕机,导致原本由缓存处理的请求全部堆积到数据库。
    • 场景:批量设置了相同的 TTL(过期时间)、Redis 集群故障。
    • 方案:TTL 增加随机抖动、搭建 Redis 高可用架构(哨兵/集群)、多级缓存(本地内存缓存)、熔断降级。

🎤 版块 B:面试实战版 (高手逐字稿)

Q:什么是缓存击穿、缓存穿透、缓存雪崩?

💬 高手逐字稿

这三个问题本质上都是“缓存层失效导致数据库压力过大”的不同表现形式。

首先说缓存穿透。这种情况是请求了“根本不存在”的数据。因为缓存和数据库都没有,所以请求每次都会穿过缓存层打到 DB。解决这个问题的核心思想是“提前拦截”和“结果记录”。我通常会先在业务层做基础校验,过滤非法请求;然后使用布隆过滤器,在请求到达数据库前判断数据是否存在;对于确实不存在的数据,我们也可以在 Redis 里存一个空值并设置较短的过期时间,防止同 ID 的重复攻击。

接下来说缓存击穿。它指的是“热点 Key 失效”。比如一个爆款商品的抢购,当这个 Key 到期的瞬间,成千上万的请求会绕过缓存去查数据库。针对击穿,我有两种成熟的方案:一种是互斥锁(SETNX)。只有拿到锁的那个线程去查库并更新缓存,其他线程等待或重试,这保证了强一致性,但会有一定的性能损耗。另一种是逻辑过期。我们不在 Redis 里设置 TTL,而是把过期时间写在 Value 里。当线程发现逻辑过期时,通过开启一个后台异步线程去查库更新,自己先返回旧数据。这种方式侧重于高可用性,适合对数据一致性要求不那么极端的场景。

最后是缓存雪崩。它是大面积的 Key 同时失效,或者 Redis 整个挂掉了。如果是由于过期时间太集中导致的,我会给每个 Key 的 TTL 加上一个随机的偏差值(比如 1-5 分钟的抖动),防止集体过期。如果是 Redis 宕机导致的,那就得靠架构层面的保障了,比如开启 Redis 的哨兵模式或集群部署实现高可用。同时,我会配合 Hystrix 或 Sentinel 进行熔断降级,防止 DB 被瞬间流量压死,并考虑引入二级缓存(比如 Caffeine)作为最后的防线。

这里其实有一个容易被忽略的细节:在解决击穿问题使用互斥锁时,如果查库并回写缓存的过程比较耗时,可能会导致大量线程阻塞在等待锁的环节。 所以在实战中,我会给互斥锁加上一个合理的超时时间,或者采用 Double Check(双重检查锁定)机制,在拿到锁后再次确认缓存是否已被前一个线程更新,避免重复查询 DB。

回答完毕。

最后更新于:
⏱️

登录后开始阅读

当前 MVP 版本只开放邮箱密码登录注册。完成登录后即可进入面试题内容。

还没有账号?先去注册