防止 Redis 缓存雪崩的核心是在写入缓存时为每个 Key 的过期时间添加随机偏移量,避免批量 Key 在同一秒集中失效。该方案适用于高并发读取场景,但需注意随机范围不宜超过基础 TTL 的 20%,否则可能导致数据过早过期。
先说结论:必须在应用层写入缓存时原子设置带随机偏移的过期时间,禁用 SET+EXPIRE 两步操作。
- 适合批量写入缓存、定时任务刷新场景
- 先做基础 TTL 上加 5%-20% 随机扰动
- 再验证数据库请求峰值是否平滑
命令速用版
使用原子命令 SET 带 EX 参数,避免分离操作。Redis 2.6.12 及以上版本支持 SET EX 原子命令。
SET key value EX 3600
Java 示例中添加随机 jitter:
int jitter = ThreadLocalRandom.current().nextInt(0, (int) (baseSeconds * 0.1)); redisTemplate.set(key, value, Duration.ofSeconds(baseSeconds + jitter));
为什么会这样
固定 TTL 会导致批量 Key 同一秒过期,请求瞬间穿透到数据库。
当批量写入缓存时,若全部使用固定过期时间,所有 Key 会在同一秒触发清理。此时 Redis 主线程可能卡在内存回收上,数据库请求量瞬间翻倍,导致连接池打满或慢查询堆积。
分步处理
- 确定基础 TTL:根据业务可接受的最短有效时间设定,例如库存数据必须 10 分钟内刷新,则 base_ttl = 600 秒。
- 计算随机偏移:在应用层生成随机值,范围建议为基础 TTL 的 5%-20%。例如 3600 秒对应±360 秒。
- 原子写入缓存:使用 SET key value EX seconds 命令,确保写入和过期时间设置是原子操作。
- 互斥锁控制重建:缓存失效后,只让第一个请求去加载数据库,其余请求等待结果,避免并发查库。
- 双层缓存兜底:主缓存失效时,先查备份缓存(TTL 更长),避免请求直接砸向数据库。
怎么验证是否生效
通过监控指标确认过期时间是否分散,数据库压力是否平稳。
- 检查 Redis 监控:观察 expired_keys 指标是否不再出现整点尖峰。
- 检查数据库监控:确认 Threads_running 不再随缓存过期时间波动。
- 扫描 Key 过期时间:使用 redis-cli `--scan` 配合 ttl 命令,确认同一批 Key 的剩余生存时间存在差异。
常见坑
- 非原子操作:禁止先 SET 再 EXPIRE,中间网络中断会导致 Key 永不过期。
- 伪随机复用:循环外生成一个 jitter 值复用到所有 Key 上,结果还是集体失效。
- 随机范围过大:偏移超过基础 TTL 的 20%,会导致部分 Key 实际存活时间严重缩水。
- 热点 Key 特殊处理:对强一致性要求的 Key 不参与随机,改用精确控制或后台刷新。
常见问题
Redis 本身提供自动打散过期时间的功能吗?
不提供,必须在应用层为每个 SET 命令的 EX 参数手动加随机偏移。
随机偏移量是不是越大越好?
不是,偏移过大会导致部分 Key 寿命缩水严重,建议控制在基础 TTL 的 5%-20% 区间。
Redis 宕机了怎么防止雪崩?
需叠加本地缓存作为第一道缓冲,并配置数据库熔断降级,避免所有请求 100% 打库。
参考来源
- Redis 如何防止大规模缓存同时失效导致雪崩
- 怎样在生产环境动态调整 Redis 过期时间防止雪崩_引入随机因子算法
- 怎么防止 Redis 缓存雪崩导致数据库宕机_设置 Key 过期时间随机扰动
- 如何应对 Redis 大规模 Key 同时过期导致的雪崩_通过设置随机过期时间差
- Redis 为什么要避免将所有 Key 设置相同的过期时间_增加随机过期时间防止雪崩效应
- Redis 集群环境下怎样预防缓存雪崩_合理规划不同节点的过期时间
- 【Spring Data Redis 过期时间深度解析】:掌握 5 种高效设置策略,避免缓存雪崩
- Redis——缓存雪崩问题
- redis 如何避免雪崩 redis 雪崩预防的 5 种解决方案
- 解决 Redis 缓存雪崩问题