一、缓存穿透(Cache Penetration)
什么是缓存穿透?
查询一个数据库中本来就不存在的数据。
流程:
用户请求
│
▼
Redis(没有)
│
▼
MySQL(没有)
每次请求都会访问 MySQL。
例如:
查询 user:999999
数据库中根本不存在。
为什么危险?
如果有人恶意不断请求不存在的数据:
100 万次请求
↓
100 万次 MySQL 查询
数据库压力会很大。
企业解决方案
① 缓存空值(推荐)
数据库没有数据时:
Redis:
user:999999
NULL
TTL=60 秒
下次直接返回,不再查询 MySQL。
② 布隆过滤器(Bloom Filter)
在查询 Redis 之前,先判断数据是否可能存在。
如果一定不存在,直接返回,不访问 Redis 和 MySQL。
适用于海量数据场景。
二、缓存击穿(Cache Breakdown)
什么是缓存击穿?
热点数据刚好过期,大量请求同时访问数据库。
流程:
热门商品
↓
Redis 过期
↓
10000 人同时访问
↓
MySQL
数据库瞬间压力暴增。
企业解决方案
① 互斥锁(推荐)
第一个请求查询 MySQL。
其他请求等待。
查询完成后写入 Redis,再继续访问。
② 热点数据永不过期
由后台主动更新缓存,而不是依赖 TTL。
适用于热点数据。
三、缓存雪崩(Cache Avalanche)
什么是缓存雪崩?
大量缓存同时过期,导致请求全部落到 MySQL。
例如:
100 万个 Key
TTL 都是 3600 秒
↓
同一时间过期
↓
全部访问 MySQL
企业解决方案
① 随机过期时间(推荐)
不要统一设置:
3600 秒
改为:
3600~3900 秒
让缓存分批过期。
② Redis 高可用
部署主从、哨兵或集群,避免 Redis 故障导致缓存全部失效。
四、三者区别
| 问题 | 原因 | 影响 | 解决方案 |
|---|---|---|---|
| 缓存穿透 | 查询不存在的数据 | MySQL 被频繁查询 | 缓存空值、布隆过滤器 |
| 缓存击穿 | 热点 Key 过期 | 大量请求访问 MySQL | 互斥锁、热点数据不过期 |
| 缓存雪崩 | 大量 Key 同时过期 | MySQL 瞬间压力暴增 | 随机 TTL、Redis 高可用 |
五、企业最佳实践
- 缓存穿透:缓存空值 + 布隆过滤器
- 缓存击穿:互斥锁 + 热点数据永不过期
- 缓存雪崩:随机 TTL + Redis 高可用
六、本章总结
| 知识点 | 核心内容 |
|---|---|
| 缓存穿透 | 查询不存在的数据 |
| 缓存击穿 | 热点 Key 过期 |
| 缓存雪崩 | 大量 Key 同时过期 |
| 缓存空值 | 防止穿透 |
| 布隆过滤器 | 快速判断数据是否可能存在 |
| 互斥锁 | 防止击穿 |
| 随机 TTL | 防止雪崩 |
本章一句话总结
穿透查不到数据,击穿热点数据过期,雪崩大量数据同时过期;企业通常通过缓存空值、互斥锁和随机 TTL 来解决。
思考题(精简回答)
-
什么是缓存穿透?为什么它会导致 MySQL 压力增大? 缓存穿透是指查询不存在的数据,Redis 和 MySQL 都没有结果。大量请求会绕过 Redis,直接访问 MySQL,导致数据库压力增大。
-
缓存空值为什么可以解决缓存穿透?它有什么缺点? 查询不到数据时,把空结果也缓存到 Redis。下次相同请求直接返回空,不访问 MySQL
缺点:占用Redis空间,如果数据后来新增,不访问mysql
-
什么是缓存击穿?为什么热点数据更容易发生击穿? 存击穿是指热点 Key 过期瞬间,大量请求同时访问数据库。热点数据访问量大,一旦失效,会同时产生大量数据库请求。
-
为什么使用互斥锁可以解决缓存击穿? 互斥锁可以保证只有一个请求查询 MySQL 并更新缓存。其他请求等待缓存生成,避免大量请求同时访问数据库。
-
什么是缓存雪崩?为什么给缓存设置随机过期时间可以缓解雪崩? 存雪崩是指大量缓存 Key 同时过期,导致请求全部访问 MySQL。设置随机 TTL 可以让 Key 分散过期,避免数据库瞬间承受大量请求
-
缓存穿透、缓存击穿、缓存雪崩三者最大的区别是什么?请分别用一句话概括。
缓存穿透:查询不存在的数据,绕过缓存访问数据库
缓存击穿:热点数据过期,大量请求访问数据库
缓存雪崩:大量缓存同时失效,倒是数据库压力暴涨