★ 缓存穿透、缓存击穿、缓存雪崩分别是什么?如何应对?

结论先行:三个问题都是“缓存缺失/失效导致请求直达数据库”的形态差异——穿透是查询根本不存在的 key,永远绕过缓存打库(常见于恶意扫描);击穿是某个热点 key 在过期瞬间被大量并发同时回源;雪崩是大量 key 同时失效或缓存整体宕机,流量洪峰直接压垮数据库。对策主线:穿透用“空值缓存 + 布隆过滤器 + 入参校验”;击穿用“互斥重建 / 逻辑过期”;雪崩用“过期时间加随机抖动 + 缓存高可用 + 限流降级兜底”。

三兄弟对比表

问题表象典型场景核心对策
穿透永远查不到扫描不存在的 id空值缓存、布隆过滤器、入参校验
击穿单个热点 key 过期爆款商品/秒杀详情互斥重建、逻辑过期、永不过期+异步刷新
雪崩大批 key 同时失效/宕机缓存集体到期、节点故障过期加随机值、集群高可用、限流降级

防击穿:互斥重建(伪代码)

// 热点 key 过期瞬间,只允许一个请求回源重建缓存
Object v = cache.get(key);
if (v == null) {
    synchronized (lock(key)) {      // 单机用 synchronized;多机改用 Redis SETNX
        v = cache.get(key);         // 双重检查,避免重复回源
        if (v == null) {
            v = db.query(key);
            cache.set(key, v, ttl + random()); // 过期时间加随机值,兼防雪崩
        }
    }
}

兜底与降级(多一层防护)

  • 即使做了互斥重建,回源流量仍可能打爆 DB → 对热点 key 单独限流;
  • 缓存集群整体故障瞬间 → 进程内本地缓存(多级缓存)先顶上;
  • 数据库侧保留降级开关:极端情况下直接返回降级文案或默认数据;
  • 监控三个指标:穿透量、回源重建量、成批失效 key 数,报警才有依据。

布隆过滤器示意(伪代码)

// 布隆过滤器可拦截“一定不存在”的 key,DB 零压力
if (!bloom.mightContain(key)) {
    return null; // 一定不存在,直接返回
}
Object v = cache.get(key); // 可能存在 → 走缓存再回源

常见追问 / 记忆点

  • 追问:布隆过滤器为什么能防穿透?答:把存在的 key 哈希到位图,查询时不在位图直接返回,能拦下绝大多数不存在的 key;代价是“存在”可能误判。
  • 追问:缓存不设过期时间可行吗?答:可配合“逻辑过期 + 异步重建”,但要接受短暂不一致窗口,并控制内存占用。
  • 记忆点:穿透查“空”、击穿挂“热点”、雪崩炸“一片”;对策口诀——空值/布隆、互斥/逻辑过期、随机抖动/多级缓存。
笔记加载中…