用真实场景拆解 Redis 缓存穿透、击穿、雪崩的区别,以及对应处理方案。

Redis 缓存穿透、击穿、雪崩怎么区分?一篇讲清
/ Update
8 mins
1643 words
Loading views

Redis 缓存穿透、击穿、雪崩怎么区分?一篇讲清h1

我是怎么把这三个词分清的h2

刚学 Redis 时,我最容易混淆的三个词就是:

  • 缓存穿透
  • 缓存击穿
  • 缓存雪崩

它们看起来都像“缓存出问题了”,但真正做题或者面试时,如果说不清区别,就很容易越讲越乱。

我之前也是背概念背得很痛苦,后来换了一个方式:从“是什么请求打到了数据库”这个角度来分。

后来我换了个记法,不再背定义,而是先问自己一句:“这波请求为什么会打到数据库?”

这篇就是按这个思路整理的版本。

先把核心区别写清楚h2

  • 缓存穿透:查的是根本不存在的数据,缓存和数据库都没有
  • 缓存击穿:一个热点 Key 过期了,大量并发同时打到数据库
  • 缓存雪崩大量 Key 在同一时间失效,导致请求大面积打到数据库

一句话区分:

  • 穿透:查不到
  • 击穿:热点过期
  • 雪崩:大面积过期

一、缓存穿透是什么h2

典型场景h3

比如你要查商品 id=99999999,但这个商品本来就不存在。

正常流程是:

请求 -> Redis 没命中 -> 查数据库 -> 数据库也没有 -> 返回空

如果有人反复请求这种不存在的数据,请求就会不断绕过缓存,直接打到数据库。

这就叫缓存穿透

为什么危险h3

因为攻击者或者异常流量可以专门构造不存在的 Key,不停请求,让数据库白白承压。

常见解决方案h3

方案一:缓存空值h4

如果数据库查出来是空,也往 Redis 里写一个短期空值:

String cache = stringRedisTemplate.opsForValue().get(key);
if (cache != null) {
if (cache.isEmpty()) {
return null;
}
return JSONUtil.toBean(cache, Shop.class);
}
Shop shop = getById(id);
if (shop == null) {
stringRedisTemplate.opsForValue().set(key, "", 2, TimeUnit.MINUTES);
return null;
}

这样后面的相同请求就会直接命中“空值缓存”,不会一直打数据库。

方案二:布隆过滤器h4

适合数据量大、查询频繁的场景。

思路是:请求先过布隆过滤器,如果它判断“这个 Key 不可能存在”,那就直接拦掉,不再查 Redis 和数据库。

适用思路h3

  • 简单业务:优先缓存空值
  • 大流量场景:布隆过滤器 + 空值缓存

二、缓存击穿是什么h2

典型场景h3

某个热点商品平时访问量很高,Redis 中一直有缓存。

但这个热点 Key 突然过期了,这一瞬间大量请求同时进来,发现缓存没了,就一起查数据库。

热点请求 -> 热点 Key 过期 -> 大量并发同时查库

这就是缓存击穿

关键点h3

击穿不是“大量不同 key 出问题”,而是:

一个很热的 key,在某个时间点失效了。

常见解决方案h3

方案一:互斥锁h4

只允许一个线程去重建缓存,其他线程等待或重试。

方案二:逻辑过期h4

缓存里存真实数据 + 逻辑过期时间。即使过期,也先返回旧值,再异步重建。

我的理解h3

击穿重点不是“缓存没有了”,而是“热点数据没了”。

所以它和穿透最大的区别是:

  • 穿透:数据本来就没有
  • 击穿:数据本来有,只是热点缓存刚好失效

三、缓存雪崩是什么h2

典型场景h3

比如系统启动时,给一批商品缓存统一设置了 30 分钟过期。

30 分钟一到,这批缓存同时失效,于是大量请求一起查数据库。

很多 key 同时过期 -> 大量请求一起回源数据库

这就是缓存雪崩

为什么比击穿范围更大h3

  • 击穿:一般是一个热点 Key
  • 雪崩:是很多 Key 一起失效,甚至整个缓存层短时间不可用

所以雪崩的影响面通常更大。

常见解决方案h3

方案一:过期时间加随机值h4

不要让缓存整点一起过期:

long ttl = 30 + RandomUtil.randomLong(1, 10);
stringRedisTemplate.opsForValue().set(key, value, ttl, TimeUnit.MINUTES);

方案二:多级缓存h4

本地缓存 + Redis,降低全部打到数据库的概率。

方案三:限流 / 熔断 / 降级h4

当缓存层异常时,保护数据库,避免级联雪崩。

四、怎么快速区分这三个问题h2

我现在记法很简单:

问题本质常见场景解决思路
缓存穿透查不存在的数据恶意请求 / 脏请求缓存空值、布隆过滤器
缓存击穿热点 Key 过期热门商品、热点店铺互斥锁、逻辑过期
缓存雪崩大量 Key 同时失效批量缓存统一过期随机过期、限流降级、多级缓存

五、一个更实战的理解方式h2

如果把数据库看成“最后一道门”,那:

  • 穿透:门外来的人,查的是根本不存在的房间号
  • 击穿:大家都在抢同一个热门房间,但前台记录刚好失效了
  • 雪崩:整栋楼的前台记录同时丢了,所有人都挤向后台查询

这样我就不太容易混了。

我踩过的坑h2

坑 1:把穿透和击穿当成一回事h3

其实区别很关键:一个是“本来没有”,一个是“本来有但过期了”。

坑 2:只记方案,不记触发条件h3

面试时如果只会说“加布隆过滤器”“加互斥锁”,但说不清为什么,就容易显得像背答案。

坑 3:以为给缓存加过期时间就够了h3

如果所有缓存 TTL 都一样,反而更容易形成雪崩。

面试里我一般这么回答h2

可以按这个顺序讲:

  1. 穿透:查不存在的数据,解决是缓存空值或布隆过滤器
  2. 击穿:热点 Key 过期,大量并发打库,解决是互斥锁或逻辑过期
  3. 雪崩:大量 Key 同时失效,解决是随机 TTL、限流降级、多级缓存

如果面试官继续问,你还可以补一句:

我在学习时会把它们按“单 key 问题”还是“批量 key 问题”来记,这样更容易区分。

最后我怎么记这三件事h2

缓存三兄弟最核心的区别,不在名字,而在于:

是不存在的数据打库、热点数据打库,还是大面积数据一起打库。

评论