一、前言
在现代高并发系统中,缓存层(如 Redis、Memcached) 是架构中至关重要的一环。
它能极大地缓解数据库压力,提升响应速度。然而,随着系统规模增大与流量复杂化,缓存系统本身也可能成为“性能黑洞”。
在实际业务中,缓存雪崩、缓存穿透与缓存击穿 是最常见的三大问题,它们不仅可能导致缓存命中率骤降,更严重时甚至会让数据库被瞬间压垮。
本文将从底层机制、触发原因、案例剖析、以及解决方案多个维度深度分析这三种问题。
二、缓存雪崩(Cache Avalanche)
2.1 概念定义
缓存雪崩 指的是在同一时间,大量缓存数据同时过期或缓存服务不可用,导致所有请求瞬间打到数据库,造成数据库负载暴增甚至宕机。
2.2 典型场景
- 某批数据设置了相同的过期时间(例如定时任务批量刷新缓存时全部设为 1 小时后过期)。
- Redis 宕机或大规模重启,导致缓存层整体不可用。
- 高频热点数据在缓存重建过程中并发请求过多。
2.3 问题分析
缓存雪崩的根本问题在于缓存失效集中化。
当大量 key 同时过期或缓存节点失联时,系统瞬间从“高命中模式”转入“全量回源模式”,此时数据库 QPS 可能暴涨 10~100 倍,轻则性能骤降,重则直接崩溃。
2.4 解决方案
✅ 随机过期时间
避免 key 同时过期:
int expireTime = baseExpire + RandomUtils.nextInt(0, 300);
redis.set(key, value, expireTime, TimeUnit.SECONDS);
这种“抖动过期”能有效打散缓存失效时间。
✅ 互斥更新与异步重建
可通过 异步线程池刷新缓存 或 双层缓存结构(本地缓存 + Redis) 减少集中重建。
✅ 多级缓存架构
使用 L1 本地缓存(如 Caffeine) + L2 Redis 缓存 的结构,使部分请求可在本地快速命中。
✅ 服务降级与限流
在缓存层异常时,通过熔断或返回默认数据,防止数据库被打爆。
三、缓存穿透(Cache Penetration)
3.1 概念定义
缓存穿透 指的是请求的数据在缓存中不存在,并且在数据库中也不存在,每次请求都要访问数据库,造成缓存系统形同虚设。
3.2 常见场景
- 恶意攻击:大量请求随机 key,均不存在于缓存与数据库中。
- 参数异常:如用户查询 id 为
-1或超大值等非法数据。 - 业务逻辑漏洞:如查询已逻辑删除或尚未写入的数据。
3.3 问题分析
由于这些请求永远无法被缓存命中,缓存系统无法发挥作用。高并发下,这类请求会持续击打数据库,造成性能瓶颈或数据库宕机。
3.4 解决方案
✅ 缓存空值(Null 缓存)
对于不存在的数据,在缓存中存一个“空对象”并设置较短过期时间:
if (dbResult == null) {
redis.set(key, "", 60, TimeUnit.SECONDS); // 缓存空值 1 分钟
}
✅ 布隆过滤器(Bloom Filter)
在访问缓存前,利用布隆过滤器判断 key 是否可能存在:
请求流程:请求 → 布隆过滤器判断 → (不存在) → 直接拒绝
↓
(存在) → 查缓存 → 查数据库
布隆过滤器能在常数时间内判断“是否可能存在”,大幅减少无效查询。
✅ 参数校验与限流
在业务层对请求参数进行有效性验证,配合限流防止恶意请求。
四、缓存击穿(Cache Breakdown)
4.1 概念定义
缓存击穿 指的是某个热点 key 在缓存过期的一瞬间,有大量并发请求同时到达,导致瞬间全部落到数据库,造成短时间内数据库压力剧增。
区别于“雪崩”的大面积问题,击穿通常是针对单一热点 key 的突发性问题。
4.2 场景举例
- 热门商品详情页、活动页等高频访问接口。
- 热点用户资料、热搜榜等集中访问的数据。
4.3 解决方案
✅ 互斥锁(Mutex Lock)
在重建缓存时加分布式锁,防止并发请求同时查询数据库:
String lockKey = "lock:" + key;
if (tryLock(lockKey)) {
// 查询数据库并重建缓存
redis.set(key, dbResult, expire, TimeUnit.SECONDS);
unlock(lockKey);
} else {
// 等待一会再尝试获取缓存
Thread.sleep(50);
return redis.get(key);
}
✅ “逻辑过期”机制
缓存数据中保存一个逻辑过期时间字段,缓存过期后由后台线程异步更新:
{
"data": {...},
"expireTime": 1730390400
}
读取时若发现逻辑过期,则异步触发重建,主请求仍可返回旧数据,保证稳定性。
✅ 提前刷新与热点预热
对于固定热点数据,可以使用定时任务提前刷新缓存,或在系统启动时预加载。
五、对比总结
| 类型 | 问题本质 | 典型触发场景 | 主要影响 | 常用解决方案 |
|---|---|---|---|---|
| 缓存雪崩 | 大量缓存同时失效 | 大量 key 同期过期、缓存宕机 | 数据库被瞬时压垮 | 过期时间随机化、多级缓存、限流降级 |
| 缓存穿透 | 数据在缓存与数据库中都不存在 | 非法请求或恶意攻击 | 数据库持续高压 | 布隆过滤器、空值缓存、参数校验 |
| 缓存击穿 | 热点 key 突然过期 | 高频访问热点数据 | 瞬时数据库压力暴增 | 分布式锁、逻辑过期、预热机制 |
六、实践建议与最佳实践
-
缓存策略分层设计
- 对高频热点数据使用“逻辑过期 + 异步刷新”。
- 普通数据使用随机 TTL 打散过期时间。
-
结合监控与报警
- 监控 Redis 命中率、慢查询、内存使用率。
- 监控数据库 QPS 与缓存穿透比例。
-
数据防御从入口做起
- 对请求参数进行白名单与黑名单过滤。
- 建立限流与熔断机制。
-
缓存可观测性与可控性
- 提供缓存管理后台,可手动预热或失效缓存。
- 记录缓存命中日志,追踪热点 key。

5万+

被折叠的 条评论
为什么被折叠?



