通常我们为了保证缓存中的数据与数据库中的数据一致性,会给 Redis 里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到 Redis 里,这样后续请求都可以直接命中缓存。
那么,当大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机 时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。
一、缓存雪崩是怎么发生的?
大量缓存同一时间过期
Redis 整体不可用
比如:
Redis 宕机
Redis 集群网络故障
主从切换失败
二、缓存雪崩的完整过程
-
用户请求 /order/detail?id=123
-
发现 Redis key 过期
-
线程访问 MySQL
-
同一时间 1w 个请求都这么干
-
MySQL 连接池耗尽
-
接口 RT 飙升
-
服务雪崩(线程阻塞)
真正压垮系统的不是"缓存失效",而是"并发放大"
缓存雪崩的缺点
数据库 CPU 100%
连接池打满
服务线程阻塞
上游服务超时
整个系统级联故障
三、如何解决缓存雪崩?
不要让请求同时落到数据库
一、缓存层解决方案
过期时间"错峰"设置
热点数据永不过期
Redis 不设置 TTL
value 里带 expireTime
后台线程异步更新
前台永远有旧数据兜底
多级缓存
Redis 挂了:
本地缓存还能扛一部分流量
二、数据库保护措施
服务限流 & 降级
QPS 超限 → 直接返回兜底数据
保护数据库不被打死
熔断机制
DB RT 超过阈值
直接切断访问
三、架构层解决方案
Redis 高可用
主从 + Sentine
Redis Cluster
防的是 "整体不可用"型雪崩
提前预热缓存
服务启动
定时任务
热点数据先加载
一个标准的"抗雪崩方案"
-
缓存过期时间加随机值,避免同时失效
-
热点数据采用逻辑过期,异步更新
-
使用多级缓存减少 Redis 依赖
-
Redis 集群 + Sentinel 保证高可用
-
接口层做限流、降级、熔断