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
可以按这个顺序讲:
- 穿透:查不存在的数据,解决是缓存空值或布隆过滤器
- 击穿:热点 Key 过期,大量并发打库,解决是互斥锁或逻辑过期
- 雪崩:大量 Key 同时失效,解决是随机 TTL、限流降级、多级缓存
如果面试官继续问,你还可以补一句:
我在学习时会把它们按“单 key 问题”还是“批量 key 问题”来记,这样更容易区分。
最后我怎么记这三件事h2
缓存三兄弟最核心的区别,不在名字,而在于:
是不存在的数据打库、热点数据打库,还是大面积数据一起打库。
评论