Redis 高并发八股文:缓存穿透、击穿、雪崩与解决方案
·
文章目录
《Redis 高并发八股文:缓存穿透、击穿、雪崩与解决方案》
一、前言:缓存为什么要防“穿、击、崩”
Redis 的引入让系统能“抗流量、快响应”,
但在高并发环境下,缓存失效或查询异常,
会导致请求集中打到数据库,形成雪崩效应。
三大典型问题:
- 穿透(Penetration) → 查的 key 根本不存在;
- 击穿(Breakdown) → 热点 key 过期瞬间;
- 雪崩(Avalanche) → 大量 key 同时过期。
一句话总结:
缓存穿透是“查不到”;
缓存击穿是“突然没了”;
缓存雪崩是“一起没了”。
二、缓存穿透(Cache Penetration)
(1)现象
请求的数据在缓存和数据库中都不存在,
每次请求都绕过 Redis 直击数据库。
当恶意请求或爬虫访问大量不存在的 key 时,
数据库压力骤增,甚至被打垮。
(2)常见原因
- 用户请求非法 ID(如 -1、0、99999999);
- 黑客恶意构造不存在 key;
- 业务逻辑返回 null 但未缓存。
(3)解决方案
| 方案 | 原理 | 优点 |
|---|---|---|
| 缓存空值 | 查询结果为 null 时也缓存一段时间 | 简单易实现 |
| 布隆过滤器(BloomFilter) | 在缓存前判断 key 是否可能存在 | 高效过滤不存在 key |
| 参数合法性校验 | 限制非法请求 | 降低风险源头 |
示例代码:
String value = redis.get(key);
if (value == null) {
if (!bloomFilter.contains(key)) return null; // 过滤
value = db.query(key);
if (value == null)
redis.setex(key, "NULL", 60); // 缓存空值1分钟
else
redis.setex(key, value, 3600);
}
三、缓存击穿(Cache Breakdown)
(1)现象
某个热点 key(访问频率极高)突然过期,
在失效瞬间,所有请求同时打到数据库。
(2)典型案例
双十一秒杀场景中,一个商品详情缓存过期,
成千上万请求瞬间查询数据库 → 瞬时高峰宕机。
(3)解决方案
| 方案 | 思路 | 适用场景 |
|---|---|---|
| 互斥锁(Mutex) | 第一个请求构建缓存,其他请求等待 | 热点 key 稳定场景 |
| 逻辑过期 | 缓存内保存逻辑时间,异步更新 | 高性能系统(如热点数据) |
| 永不过期 + 异步刷新 | 不设置 TTL,由后台定时任务更新 | 高 QPS 低变动数据 |
示例:逻辑过期 + 异步刷新
class CacheData {
Object data;
long expireTime; // 逻辑过期时间
}
CacheData cache = redis.get(key);
if (cache != null && cache.expireTime > System.currentTimeMillis()) {
return cache.data;
} else {
// 异步线程刷新
if (lock.tryLock()) {
threadPool.submit(() -> {
Object newData = db.query(key);
redis.set(key, new CacheData(newData, now+10min));
lock.unlock();
});
}
return cache.data; // 返回旧值
}
用户永远有数据看,后台异步更新;
稍微复杂,但能应对高并发。
四、缓存雪崩(Cache Avalanche)
(1)现象
大量 key 在同一时间过期或缓存服务器宕机,
所有请求同时访问数据库 → 雪崩式崩溃。
(2)常见原因
- 定时批量刷新缓存;
- 使用固定 TTL;
- Redis 故障。
(3)解决方案
| 防护措施 | 说明 |
|---|---|
| 过期时间随机化 | TTL = base + random(0, N) 避免同时过期 |
| 多级缓存 | Redis + 本地缓存(Caffeine、Guava) |
| 热点数据永不过期 | 主动更新而非被动过期 |
| 服务熔断限流 | 使用 Sentinel / Hystrix / Resilience4j |
| Redis 集群高可用 | 主从 + 哨兵 / Cluster 模式容灾 |
示例:
int base = 3600; // 1小时
int random = new Random().nextInt(300);
redis.setex(key, value, base + random); // TTL随机化
五、三者区别一览(面试必背表)
| 对比项 | 穿透 | 击穿 | 雪崩 |
|---|---|---|---|
| 问题本质 | 查不存在的数据 | 热点数据过期瞬间 | 大量缓存同时失效 |
| 影响范围 | 局部或单 key | 单热点 key | 全局多 key |
| 是否可控 | 可通过布隆过滤器预防 | 可用互斥锁或逻辑过期 | 可用随机 TTL 或多级缓存 |
| 典型场景 | 恶意请求、空值 | 秒杀商品详情 | 定时刷新、Redis宕机 |
| 核心解决策略 | 过滤 + 空值缓存 | 锁 + 逻辑过期 | 随机TTL + 熔断 + 集群 |
六、面试高频问题与答题模板
| 问题 | 答案要点 |
|---|---|
| Q1:缓存穿透是什么? | 查询不存在的数据,缓存和数据库都未命中。 |
| Q2:如何解决缓存穿透? | 缓存空值、使用布隆过滤器、参数校验。 |
| Q3:缓存击穿是什么? | 热点 key 过期瞬间并发访问数据库。 |
| Q4:如何解决缓存击穿? | 加互斥锁、逻辑过期、后台异步刷新。 |
| Q5:缓存雪崩是什么? | 大量 key 同时过期或 Redis 故障,导致请求打穿数据库。 |
| Q6:如何解决缓存雪崩? | TTL 随机化、多级缓存、限流熔断、集群高可用。 |
| Q7:三者的区别? | 穿透:查不到;击穿:突然没;雪崩:一起没。 |
结语
缓存的核心目标是:
“让热点留在 Redis,让数据库喘口气。”
但当缓存出现“穿、击、崩”时,
再快的数据库都可能被拖垮。
掌握这三种场景与防护方案,
不仅能在面试中轻松拿下高并发题,
也能在实际项目中写出真正抗压的缓存系统。
更多推荐

所有评论(0)