一、核心概念与成因
- 缓存穿透
定义:请求一个缓存和数据库中都不存在的数据,导致每次请求都绕过缓存直接查数据库。因为数据不存在,缓存永远无法命中,这类请求会持续冲击数据库。
典型场景:黑客构造大量无效 Key(如用户 ID=-1、商品 ID=999999)发起攻击;前端传入非法参数,后端未校验直接查询。 - 缓存击穿
定义:一个热点 Key(如秒杀商品、首页热点数据)突然失效(过期 / 被删除),此时大量并发请求同时访问该 Key,全部穿透到数据库,瞬间压垮数据库。
核心特点:数据在数据库中存在,但缓存中临时缺失,且该 Key 是高并发访问的热点。 - 缓存雪崩
定义:大量缓存 Key同时失效(如缓存集群宕机、批量 Key 过期时间设置相同),导致所有请求瞬间全部冲击数据库,引发数据库宕机,甚至整个系统雪崩。
核心区别:击穿是 "单个热点 Key 失效",雪崩是 "大量 Key 集体失效 / 缓存服务不可用",影响范围更大。
二、针对性解决方案
- 缓存穿透:拦截 "无效请求"
核心思路:提前拦截不存在的 Key,避免其到达数据库。
| 解决方案 | 实现方式 | 适用场景 |
|---|---|---|
| 参数校验(首选) | 网关 / 业务层过滤非法参数:如 ID≤0、格式错误、超出合理范围的 Key 直接返回 "参数无效" | 所有场景,成本最低、效果最直接 |
| 空值缓存 | 数据库查询无结果时,将该 Key 对应的空值(如null)写入缓存,设置短期过期时间(5-10 分钟) | 非恶意的少量无效请求,避免重复查库 |
| 布隆过滤器 | 启动时将数据库中所有有效 Key 预加载到布隆过滤器(一种高效的存在性判断数据结构),请求先过过滤器:Key 不存在则直接拦截 | 高并发、大量无效请求场景(如电商商品 ID 查询) |
- 缓存击穿:保护 "热点 Key"
核心思路:避免热点 Key 失效后,大量请求同时查库。
| 解决方案 | 实现方式 | 适用场景 |
|---|---|---|
| 热点 Key 永不过期 | 核心热点 Key(如首页数据、秒杀商品)不设置过期时间,通过后台异步任务定期更新缓存 | 热点数据更新频率低的场景 |
| 分布式互斥锁 | 缓存失效时,只有一个请求能获取分布式锁(如 Redis 的 SETNX),去数据库查数据并更新缓存;其他请求等待锁释放后直接查缓存 | 高并发、热点 Key 需定期更新的场景 |
| 缓存预热 | 系统启动前 / 高并发场景(秒杀)前,主动将热点 Key 加载到缓存中 | 可预测的高并发场景(如大促、秒杀) |
- 缓存雪崩:避免 "集体失效"
核心思路:分散缓存过期时间,提升缓存服务可用性,降低数据库压力。
| 解决方案 | 实现方式 | 适用场景 |
|---|---|---|
| 过期时间随机化 | 给每个 Key 的过期时间增加随机值(如基础过期 1 小时 ± 10 分钟),避免批量 Key 同时过期 | 所有场景,基础解决方案 |
| 缓存集群高可用 | 部署 Redis 集群(主从 + 哨兵 / Redis Cluster),避免单节点宕机导致缓存服务不可用 | 生产环境必备 |
| 降级限流 | 数据库压力过大时,对非核心业务请求降级(返回兜底数据)或限流(限制每秒请求数) | 缓存集群故障时的应急方案 |
| 多级缓存 | 增加本地缓存(如 Caffeine)+ 分布式缓存,即使分布式缓存失效,本地缓存仍能承接部分请求 | 核心业务高可用要求场景 |
三、三类问题核心对比
| 特性 | 缓存穿透 | 缓存击穿 | 缓存雪崩 |
|---|---|---|---|
| 数据存在性 | 缓存 + 数据库都不存在 | 数据库存在、缓存不存在 | 数据库存在、缓存批量失效 |
| 触发规模 | 单个无效 Key 持续请求 | 单个热点 Key 并发请求 | 大量 Key / 缓存服务故障 |
| 核心风险 | 数据库持续接收无效请求 | 数据库瞬间高并发 | 数据库整体被压垮 |
| 核心解决思路 | 拦截无效请求 | 保护热点 Key | 避免批量失效 + 高可用 |