缓存雪崩及解决方案
一、什么是缓存雪崩?
缓存雪崩(Cache Avalanche) 是指大量缓存 Key 在同一时间失效,或者 Redis 服务发生故障,导致大量请求无法命中缓存,集中访问 MySQL,造成数据库压力激增,甚至导致系统崩溃。
主要有两种场景:
1. 大量 Key 同时过期
大量缓存 Key 同时过期
↓
Redis 缓存未命中
↓
大量请求访问 MySQL
↓
数据库压力激增2. Redis 服务宕机
Redis 服务不可用
↓
缓存查询失败
↓
大量请求回源 MySQL
↓
数据库压力激增注意:大量 Key 同时过期并不意味着 Redis 宕机;Redis 宕机后也不一定会直接访问 MySQL,具体取决于系统的降级和异常处理策略。
二、解决方案
1. 设置随机 TTL
避免大量 Key 在同一时间过期,可以在基础 TTL 上增加随机时间。
例如,原本所有 Key 都设置 30 分钟过期:
redisTemplate.opsForValue()
.set(key, value, 30, TimeUnit.MINUTES);优化后:
// 基础30分钟,随机增加0~10分钟
int ttl = 30 + ThreadLocalRandom.current().nextInt(11);
redisTemplate.opsForValue()
.set(key, value, ttl, TimeUnit.MINUTES);这样不同 Key 的过期时间就会分散,降低缓存同时失效的风险。
适用场景:大量 Key 同时过期。
2. Redis 高可用
通过 Redis Sentinel(哨兵)或 Redis Cluster(集群)实现高可用。
例如:
Redis 主节点 A
↓ 主从复制
Redis 从节点 B
主节点 A 宕机
↓
故障自动转移
↓
从节点 B 晋升为主节点
↓
恢复缓存服务注意:
主从复制用于数据同步,故障转移依赖 Sentinel 或 Cluster 等机制。
故障切换需要一定时间,并非完全无感。
Redis 高可用不能完全替代限流和降级措施。
适用场景:Redis 节点故障或服务不可用。
3. 限流、降级和熔断
当 Redis 出现异常或数据库压力过大时,需要保护后端系统。
① 限流
限制请求数量,例如每秒最多处理 1000 个请求,超过限制的请求直接拒绝或排队。
常见实现:Redis + Lua、Sentinel(阿里巴巴开源的流量治理组件)、Spring Cloud Gateway。
② 降级
暂时关闭非核心功能,或者返回默认数据、兜底结果。
例如:商品推荐服务异常时,暂时返回默认推荐列表,而不是继续大量查询 MySQL。
③ 熔断
当 Redis 或下游服务持续异常时,暂时停止访问故障服务,避免大量请求反复失败。
需要注意:
限流:控制请求数量。
降级:降低功能或服务质量。
熔断:暂时停止对异常依赖的调用。
适用场景:缓存服务故障或数据库访问压力过大。
4. 多级缓存
通过多层缓存降低对 Redis 和 MySQL 的依赖。
例如:
客户端请求
↓
浏览器缓存
↓ 未命中
Nginx 缓存
↓ 未命中
JVM 本地缓存(Caffeine)
↓ 未命中
Redis 分布式缓存
↓ 未命中
MySQL 数据库常见缓存层:
注意:
多级缓存需要考虑数据一致性。
不同业务不一定需要所有缓存层。
JVM 本地缓存常见实现是 Caffeine,属于第三方依赖,不是 Java 8 自带的。
各层缓存应根据数据特点设计,避免所有缓存同时过期。
适用场景:高并发读取、热点数据访问。
三、其他优化方案
1. 缓存预热
系统启动或活动开始之前,提前将热点数据加载到 Redis。
这样可以避免大量请求同时查询 MySQL。
2. 互斥锁重建缓存
缓存失效时,通过互斥锁控制只有一个线程查询数据库并重建缓存,避免同一个 Key 被大量并发请求重复查询。
该方案主要用于解决缓存击穿,也能缓解雪崩过程中单个 Key 的并发重建问题。
但对于大量不同 Key 同时失效,仍需要结合随机 TTL、限流等方案。
四、缓存穿透、击穿、雪崩的区别
五、面试总结
Redis 缓存雪崩是指大量缓存 Key 同时失效,或者 Redis 服务不可用,导致大量请求集中访问数据库,造成数据库压力激增。
常见解决方案有:
随机 TTL:给不同 Key 设置不同的过期时间,避免集中失效。
Redis 高可用:通过 Sentinel 或 Cluster 实现故障转移,降低单节点故障的影响。
限流、降级、熔断:限制请求数量,暂时关闭非核心服务,避免故障扩大。
多级缓存:使用浏览器、Nginx、JVM 本地缓存及 Redis,分散缓存访问压力。
缓存预热:提前加载热点数据,避免集中回源数据库。
实际生产中,通常需要根据业务特点组合使用多种方案。
核心记忆:
随机 TTL:防止缓存同时过期。
Redis 高可用:减少 Redis 故障影响。
限流降级:保护数据库和核心业务。
多级缓存:分散访问压力。
缓存预热:提前准备热点数据。
