缓存雪崩的两种场景
实际开发中,缓存雪崩分两种完全不同的诱因,解决方案也完全不同,必须分开处理。
场景1:大面积缓存key同时过期(最常见)
开发时给大量缓存设置了相同的过期时间,到了时间点所有key集中失效,瞬间所有读请求都绕过Redis,直接查询数据库。
场景2:Redis实例整体不可用(高风险)
Redis服务本身宕机、断网、内存溢出OOM、被误操作关停等,导致整个缓存层彻底不可用,所有请求直接穿透到数据库。
解决方案
1. 针对「大面积key同时过期」的解决方案
核心思路是打散过期时间,避免集中失效 。
不给同一批数据设置完全相同的过期时间,在基础时间上加一个随机值,把过期时间打散。
java
"错误写法:统一1小时过期,容易集中失效"
redisTemplate.opsForValue().set("product:" + productId, product, 3600, TimeUnit.SECONDS);
"正确写法:基础1小时 + 0~300秒随机偏移,错开过期"
int baseTime = 3600;
int randomOffset = new Random().nextInt(300);
redisTemplate.opsForValue().set("product:" + productId, product, baseTime + randomOffset, TimeUnit.SECONDS);
这样所有商品的过期时间分布在59~65分钟之间,不会出现同一时间几万条key同时过期的情况。
2. 分级缓存策略
按数据热度设置不同的过期时间,热点数据长过期/永不过期,冷数据短过期,从根源上减少同时过期的量级。
- 热点数据(如首页Top100商品、分类导航):设置1天过期,后台异步定时更新,永不过期
- 普通数据(如普通商品详情):1小时+随机偏移
- 冷数据(如冷门商品、历史订单):10分钟,过期了也不会有大量请求
3. 缓存预热 + 定时刷新
不要等用户请求触发缓存加载,系统启动或低峰期提前把热点数据加载到缓存;
并且通过定时任务分批异步刷新 缓存,而不是等过期后由用户请求重建。
比如,电商大促前,用脚本提前把所有活动商品缓存写入Redis,过期时间错落设置;凌晨2点低峰期,分批刷新全量商品缓存,避免白天高峰期缓存失效。
开发避坑总结
- 永远不要给批量缓存设置完全相同的过期时间,加随机偏移是成本最低的防雪崩手段
- 生产环境Redis必须集群部署,禁止单节点
- 核心业务一定要做二级缓存(本地 + 远程)和熔断降级,给自己留兜底
- 做好监控:Redis命中率、过期key数量、数据库QPS/CPU,这几个指标是雪崩的"预警灯"
- 上线前做压测:模拟缓存集中失效、Redis宕机的场景,验证系统的抗压能力