Skip to content

06 · 缓存三大问题:击穿 / 穿透 / 雪崩 ​

三个名字容易混,但机制完全不同:击穿是热 key 失效瞬间、穿透是查不存在的 key、雪崩是大批 key 同时失效。本篇给每个问题的触发条件、判断口诀与兜底手段。

速览卡 ​

项内容
一句话定位缓存失效瞬间的三种流量尖峰:机制、口诀、兜底
核心内容击穿/穿透/雪崩的区分、互斥锁、空值缓存、过期时间打散、限流降级
读完能回答热点 key 失效为什么能把 DB 打挂?缓存和 DB 都没有的数据怎么防穿透?
相关板块DB05 Redis 与缓存模式 | C13 缓存与 Redis | C21 AI 服务可靠性

一、一张表分清三个问题 ​

问题触发口诀受影响
击穿一个热点 key 失效瞬间,大量并发去回源"一个 key 挂了"单个热点
穿透查的 key 根本不存在,缓存永远为空,全打 DB"查不存在的东西"恶意/空数据
雪崩一大批 key 同时失效,一起回源"一批 key 同时挂"全局

记忆锚点:穿透是"从没有",击穿是"突然没了",雪崩是"一起没了"。


二、缓存击穿:热点 key 失效 ​

机制:user:hot 没缓存时,1000 个并发请求同时发现 miss,一起打 DB。

兜底 ​

手段做法
互斥锁(Mutex)只有一个请求回源重建,其余等缓存回来
逻辑过期值里带过期时间,读到过期就后台异步刷新,不阻塞读
热点预埋大促前主动把热 key 刷进缓存并续期
python
# 互斥锁伪代码:只允许一个线程回源
def get_hot(key, rebuild):
    val = redis.get(key)
    if val:
        return val
    with redis.lock(f"lock:{key}", timeout=3):   # 拿锁
        val = redis.get(key)                     # 双检:别人可能已重建
        if val:
            return val
        val = rebuild()
        redis.set(key, val, ex=3600)
        return val

三、缓存穿透:查询不存在的数据 ​

机制:攻击者循环请求不存在的 id,缓存永远 miss,DB 被拖垮。

兜底 ​

手段做法注意
空值缓存不存在的 key 也缓存一个"空"短 TTL(如 60s)有 TTL,避免缓存堆满
布隆过滤器先判断"可能存在"再查 DB有误判率,需调参
参数校验非法/超范围 id 直接拒绝最简单,必做
限流对异常访问模式限流兜底,不解决根源

判断框架:先做参数校验 + 空值缓存(成本最低);布隆过滤器是"查询量真的很大"时的进阶手段。


四、缓存雪崩:一大批 key 同时失效 ​

机制:缓存里上万 key 同一秒过期,全部回源,DB 瞬间被压垮。

兜底 ​

手段做法
过期时间打散基础 TTL + 随机偏移(如 3600 + rand(0,600))
多级缓存本地缓存(进程内)挡第一波,Redis 挡第二波
限流 + 降级回源时对 DB 侧限流,超过阈值返回降级数据
缓存集群高可用避免"Redis 宕机"这种最极端雪崩

雪崩的另一大来源是 Redis 本身重启/故障——这要求缓存有高可用(主从/集群),不只是调 TTL。


五、统一兜底清单 ​

层手段
缓存前参数校验、布隆过滤器(防穿透)
缓存中热 key 逻辑过期、互斥锁(防击穿)
缓存 TTL加随机偏移(防雪崩)
缓存外本地二级缓存、限流降级、Redis 高可用
长期监控回源率与 DB 负载,故障前发现尖峰

六、自检清单 ​

  • [ ] 能区分击穿/穿透/雪崩的触发条件
  • [ ] 击穿用互斥锁或逻辑过期,避免热点失效打挂 DB
  • [ ] 穿透用参数校验 + 空值缓存(必要时布隆过滤器)
  • [ ] 雪崩用过期时间打散 + 多级缓存 + 限流
  • [ ] 知道 Redis 高可用也是防雪崩的一环
  • [ ] 有回源率监控,能提前发现尖峰

七、常见误区 ​

误区事实
"击穿=穿透=雪崩"机制完全不同,针对手段也不同
"设短 TTL 就防雪崩"同批同时过期才雪崩,要打散而非单纯缩短
"空值缓存占空间"设短 TTL,成本可接受
"布隆过滤器零误差"有误判率,要按数据量调位数组与哈希数
"互斥锁万能"锁内回源仍有一次 DB 压力,逻辑过期适合高并发热 key
"缓存挂了无所谓"Redis 宕机就是最大雪崩,要主从/集群高可用

八、动手练习 ​

练习 A:识别场景 ​

给出三个现象,判断分别是击穿/穿透/雪崩,并给对应兜底:

  1. 秒杀商品详情在 0 点失效后 DB 卡死
  2. 攻击者用随机 id 循环请求
  3. 凌晨缓存统一 4 点过期,DB 同时飙高

练习 B:写互斥锁 ​

用你熟悉的语言给"热点数据获取"加互斥锁 + 双检(double-check),并说明为什么需要双检。

练习 C:给 TTL 加抖动 ​

写一个"过期时间随机化"的封装:set(key, val, base_ttl),实际 TTL 在 base_ttl 到 base_ttl * 1.2 之间随机。


相关文档 ​

本区 ​

其他域 ​