Skip to content

缓存穿透/击穿/雪崩

三大经典问题现象、生活比喻、布隆过滤器数学原理、互斥锁与逻辑过期方案。

Updated View as Markdown
For humans

缓存穿透/击穿/雪崩

校招考察频度:★ 高频(核心必背·高频生死线) 一句话速记:穿透查“虚无”(库里查无此人,布隆过滤+缓存空值);击穿破“单点”(热点 Key 瞬间到期,互斥锁+逻辑过期);雪崩倒“整片”(海量 Key 同时失效或宕机,TTL 随机打散+多级缓存+熔断降级)。

面试经典高频必考三连:穿透、击穿、雪崩。虽然名字相似,但诱因和防护策略截然不同。面试时必须“先分层下定义,再给出生产解法与工程取舍”。


一、三大问题核心特征对比

异常现象现实大白话比喻攻击/故障源头最终打爆的目标
缓存穿透恶意分子拿着一个**根本不存在的身份证号(如负数 ID)**去民政局查档案,前台缓存查不到,只能每次都派人去地下档案库(数据库)掘地三尺翻找,最终把库累瘫。恶意扫描攻击或非法请求数据库(持续高压穿透)
缓存击穿某顶级顶流明星突发爆炸性新闻(超级热点 Key),刚好在热度最高峰的那一秒,该 Key 的缓存物理 TTL 刚好到期!百万并发请求同时穿破缓存直击数据库。正常海量并发 + 单点 Key 过期数据库(瞬间单点突刺)
缓存雪崩大批量的 Key 设置了完全相同的过期时间(如全设为 2 小时),到期那一刻全城停电;或者 Redis 整个集群直接物理宕机,所有请求如同雪崩般倾泻至数据库。批量过期或 Redis 宕机数据库(全盘崩溃瘫痪)

二、缓存穿透:布隆过滤器深度剖析

面对“查无此人”的查询,解法有二:

  1. 缓存空对象(Cache Null / Empty):
    • 数据库查不到时,向 Redis 写入空值(如 "" 或 {}),设置极短的 TTL(如 1~3 分钟)。
    • 缺点:如果攻击者每次换不同的无序随机 ID,依然会产生大量空 Key 占满 Redis 内存。
  2. 布隆过滤器(Bloom Filter,工业界标配):
    • 底层原理:由一个超长二进制位数组(Bit Array)和 kk 个独立的哈希函数组成。写入数据时,分别用 kk 个哈希函数计算出 kk 个位置并置为 1;查询时,必须这 kk 个位置全部为 1 才认为可能存在。
    • 铁律法则:
      • 只要有任意 1 位是 0,该数据 100% 绝对不存在(可以直接拦截,不查 DB);
      • 若全为 1,数据大概率存在,但存在一定的“假阳性/误判率(False Positive)”(因为哈希碰撞,这几位可能恰好被其他数据置为 1 了)。
    • 删除问题:标准布隆过滤器不能删除数据(清 0 可能会连带影响其他数据);若需支持删除,需采用计数布隆过滤器(Counting Bloom Filter)。

缓存击穿

现象:热点 key(如秒杀商品)在过期瞬间,大量并发请求同时 miss,一起打到数据库。

解法:

  • 互斥锁:第一个请求拿锁重建缓存,其他请求等待或返回旧值。锁粒度要细,避免串行化所有读
  • 逻辑过期:不设物理 TTL,value 里带过期时间戳;读到逻辑过期时异步重建,请求先返回旧数据。实现复杂但无锁等待

缓存雪崩

现象:大量 key 同一时刻过期(如统一 TTL),或 Redis 实例宕机,流量瞬间全部打到数据库。

解法:

  • TTL 打散:过期时间加随机值(基础值加 0 到 300 秒随机),避免整批过期
  • 多级缓存:本地缓存(如 Caffeine)挡第一层,Redis 第二层,数据库兜底
  • 高可用:哨兵/集群防单点宕机,宕机期间限流降级
  • 限流降级:数据库侧限流,返回降级数据(如旧缓存、默认值)

对比与优先级

  • 穿透和击穿、雪崩的防护可以叠加:布隆过滤器挡穿透,TTL 打散挡雪崩,互斥锁挡击穿
  • 面试话术顺序:先说现象和危害,再说方案,再说取舍(空值缓存的内存代价、布隆过滤器的误判率、锁的粒度)

面试追问

  1. 穿透和击穿的区别? 穿透是数据不存在每次打库;击穿是热点 key 过期瞬间打库。一个是”有没有”的问题,一个是”过期时机”的问题
  2. 布隆过滤器有误判吗? 有,只能保证”不存在的一定不在”,存在可能误判。误判率由位数组大小和哈希函数数控制
  3. 互斥锁怎么实现? SETNX 拿锁重建缓存,其他请求拿不到就等或返回旧值。注意锁要设过期时间防死锁
  4. 逻辑过期和互斥锁怎么选? 要求强一致用互斥锁(有短暂等待),允许短暂旧数据用逻辑过期(无等待)
  5. 雪崩的 TTL 打散怎么做? TTL = 基础时间 + 随机偏移,让过期时刻均匀分布
Navigation

Type to search…

↑↓ navigate↵ selectEsc close