目录
2.1.2 给缓存 Key 设置 “永不过期”+ 主动更新
1、概述
缓存雪崩是指大量缓存 Key 在同一时间段集中过期失效,或缓存服务(如 Redis)因故障(宕机、网络中断)整体不可用,导致原本依赖缓存的海量请求瞬间全部穿透到数据库,造成数据库 CPU、连接数飙升,最终引发数据库宕机,甚至整个业务链路瘫痪的连锁故障。
它与缓存击穿、穿透的核心区别在于:
- 击穿是 “单个热点 Key 过期” 引发的局部冲击;
- 穿透是 “查不存在的 Key” 导致的持续低效请求;
- 雪崩是 “大量 Key 集中失效 / 缓存整体不可用” 引发的全局级压力,破坏力远大于前两者。
典型触发场景:
- 缓存 Key 集中过期:比如电商大促前,为预热商品数据批量写入缓存,且统一设置了 24 小时 TTL,大促当天凌晨所有商品缓存同时过期,请求瞬间涌向数据库;
- 缓存服务故障:Redis 集群因机器断电、主从切换失败、网络分区等问题整体不可用,所有缓存查询直接失效。
危害:短时间内数据库承接远超承载能力的并发请求,可能在几秒内宕机;若数据库无容灾机制,会导致依赖该数据库的订单、支付、商品等核心接口全部报错,最终影响业务可用性。
2、解决方法
缓存雪崩的核心应对思路是 “提前预防”(避免雪崩发生)和 “事后兜底”(雪崩发生后减少损失),具体可分为 “缓存层面” 和 “数据库层面” 两类方案。
2.1 缓存层面:避免雪崩触发
2.1.1 错开缓存 Key 的过期时间
最直接的预防手段:给批量写入的缓存 Key 设置 “基础 TTL + 随机偏移量”,避免所有 Key 集中过期。
例如:原本计划给所有商品缓存设置 24 小时过期,可改为 “24 小时 + 随机 10~30 分钟”,这样缓存失效时间会分散在 24.17~24.5 小时内,避免集中失效。
// 基础TTL:24小时(单位:秒)
long baseTtl = 24 * 60 * 60;
// 随机偏移量:10~30分钟(换算成秒,范围:600~1800秒)
long randomOffset = new Random().nextInt(1200) + 600;
// 最终TTL = 基础TTL + 随机偏移量
long finalTtl = baseTtl + randomOffset;
// 写入缓存
redisTemplate.opsForValue().set("product:info:" + productId, productInfo, finalTtl, TimeUnit.SECONDS);
适用场景:批量初始化缓存(如大促预热、首页数据同步),且 Key 数量较多的场景,无额外成本,实现简单。
2.1.2 给缓存 Key 设置 “永不过期”+ 主动更新
对核心业务的缓存 Key(如首页 Banner、核心商品详情),不依赖 Redis 的 TTL 被动过期,而是:
- 缓存 Key 不设置过期时间,避免因过期失效;
- 通过定时任务(如 XXL-Job)主动拉取数据库最新数据,定期更新缓存(如每 30 分钟更新一次)。

适用场景:核心且数据更新频率低的缓存(如首页配置、活动规则),能完全避免因过期引发的雪崩,但需注意定时任务的执行频率,避免过度查询数据库。
2.1.3 缓存服务高可用:避免缓存整体不可用
通过 Redis 集群架构提升可用性,防止单点故障导致缓存整体失效:
- 主从复制:部署 1 主 N 从 Redis 集群,主节点负责写,从节点负责读,主节点故障时从节点可切换为新主,保证读请求正常;
- 哨兵模式 / Redis Cluster:哨兵模式监控主从节点,自动完成故障切换;Redis Cluster 则将数据分片存储在多个节点,单个节点故障仅影响部分数据,不影响整体缓存服务。
核心作用:即使部分缓存节点故障,缓存服务仍能正常提供服务,避免 “缓存整体不可用” 引发的雪崩。
2.2 兜底层面:雪崩发生后减少损失
2.2.1 服务降级 / 熔断:限制请求流向数据库
当缓存失效且数据库压力过高时,通过服务降级或熔断机制 “拦截” 部分请求:
- 降级:返回默认数据(如 “商品暂时无法查看,请稍后重试”),不调用数据库;
- 熔断:当数据库请求失败率超过阈值(如 50%),暂时断开数据库连接,所有请求直接返回降级结果,避免数据库被持续压垮。
实现工具:可通过 Sentinel、Hystrix 等组件实现,适合所有依赖缓存的业务,是雪崩发生后的 “最后一道防线”。
2.2.2 数据库层面:提升抗压力
- 读写分离:让读请求走从库,减轻主库压力;
- 分库分表:将数据分散到多个数据库实例,避免单库承接所有请求;
- 加数据库缓存:开启数据库自身的查询缓存(如 MySQL Query Cache,需注意适用性),或使用本地缓存(如 Caffeine)暂存高频请求数据,减少数据库直接查询。
作用:即使请求穿透到数据库,也能通过架构优化降低数据库压力,避免快速宕机。
2.2.3 本地缓存兜底:避免完全依赖 Redis
在应用服务本地(如 JVM 内存)设置一层本地缓存,存储高频访问的核心数据(如秒杀商品库存)。当 Redis 缓存失效时,先查询本地缓存,若存在则直接返回,减少穿透到数据库的请求量。
注意:本地缓存需做好更新策略(如通过消息队列同步更新),避免数据不一致,适合核心且更新频率低的数据。
3、总结
缓存雪崩的解决需 “预防为主,兜底为辅”,不同场景需结合业务特点选择方案。

- 优先通过 “错开过期时间 + 缓存高可用” 预防雪崩,这是成本最低、效果最好的方式;
- 兜底方案(降级、熔断、本地缓存)必须配置,避免因极端情况(如缓存集群整体宕机)引发业务瘫痪;
- 核心业务需组合多种方案(如 “错开过期时间 + Redis Cluster + 服务熔断”),形成多层防护,确保高可用性。
3651

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



