缓存穿透、缓存击穿、缓存雪崩的区别与解决方案
1. 缓存穿透(Cache Penetration)
-
定义:大量请求查询 数据库中不存在的数据,导致请求绕过缓存直接访问数据库,造成数据库压力过大。
-
场景:
-
恶意攻击:例如用不存在的用户ID频繁请求。
-
业务误操作:系统逻辑错误导致生成无效查询(如负数ID)。
-
-
解决方案:
-
缓存空值:对数据库查询为空的Key,缓存一个空对象(如
Null
)并设置较短过期时间。// 示例代码:缓存空值 public String getData(String key) { String value = cache.get(key); if (value == null) { value = db.query(key); if (value == null) { cache.put(key, "NULL", 60); // 缓存空值60秒 } else { cache.put(key, value); } } return "NULL".equals(value) ? null : value; }
-
布隆过滤器(Bloom Filter):在缓存层前加布隆过滤器,快速判断Key是否存在,拦截无效请求。
-
接口限流与校验:对请求参数做合法性校验(如ID范围),对异常IP限流。
-
2. 缓存击穿(Cache Breakdown)
-
定义:某个热点Key在缓存过期瞬间,大量并发请求直接穿透到数据库,导致数据库瞬时压力激增。
-
场景:
-
热搜话题、秒杀商品等热点数据过期。
-
缓存重建时间较长(如复杂计算)。
-
-
解决方案:
-
永不过期 + 异步更新:对热点Key设置逻辑永不过期,后台异步刷新。
// 示例:逻辑永不过期(实际值带过期时间,异步续期) public String getHotData(String key) { String value = cache.get(key); if (value == null) { value = reloadHotData(key); // 触发异步加载 } return value; }
-
互斥锁(Mutex Lock):缓存未命中时,通过分布式锁控制单线程重建缓存。
// 示例:Redis分布式锁(RedLock) public String getDataWithLock(String key) { String value = cache.get(key); if (value == null) { if (redisLock.tryLock(key)) { try { value = db.query(key); // 双重检查,防止重复查询 cache.set(key, value); } finally { redisLock.unlock(key); } } else { Thread.sleep(100); // 等待后重试 return getDataWithLock(key); } } return value; }
-
缓存预热:在高峰前提前加载热点数据。
-
3. 缓存雪崩(Cache Avalanche)
-
定义:大量缓存Key同时过期 或 缓存服务宕机,导致所有请求涌向数据库,引发级联故障。
-
场景:
-
缓存服务器重启。
-
批量数据设置相同过期时间(如凌晨刷新缓存)。
-
-
解决方案:
-
随机过期时间:在基础过期时间上增加随机值,分散Key失效时间。
// 示例:设置随机过期时间(30分钟±随机10分钟) int expireTime = 1800 + new Random().nextInt(600); cache.set(key, value, expireTime);
-
集群高可用:使用Redis Cluster或Sentinel保证缓存层高可用。
-
多级缓存:结合本地缓存(如Caffeine)和分布式缓存,减少对单一缓存的依赖。
// 示例:多级缓存(本地+Redis) public String getDataMultiLevel(String key) { String value = localCache.get(key); if (value == null) { value = redis.get(key); if (value != null) { localCache.put(key, value); } else { value = db.query(key); redis.set(key, value, 3600); localCache.put(key, value); } } return value; }
-
降级熔断:通过Hystrix或Sentinel实现请求限流和熔断,保护数据库。
对比总结
问题类型 | 触发条件 | 核心影响 | 典型解决方案 |
---|---|---|---|
缓存穿透 | 查询不存在的数据 | 数据库被无效查询压垮 | 布隆过滤器、缓存空值、参数校验 |
缓存击穿 | 热点Key过期 | 数据库瞬时高并发 | 互斥锁、逻辑永不过期、缓存预热 |
缓存雪崩 | 大量Key同时失效或服务宕机 | 数据库持续高压 | 随机过期时间、多级缓存、集群高可用 |
实际应用建议
-
监控与告警:实时监控缓存命中率、数据库QPS,设置阈值告警。
-
压测验证:通过模拟高并发场景测试缓存策略的有效性。
-
动态调整:根据业务变化(如突发流量)动态调整缓存策略(如自动延长热点数据过期时间)。