预热必须在零点前5~10分钟完成且避开高峰,使用分布式调度、幂等控制、离线数据、TTL打散、失败校验与兜底,仅预热高QPS热点数据。

预热时机必须卡在零点前完成,不能依赖“零点触发”
零点一到再开始预热,等于把雪崩从数据库前移到了预热任务本身——大量 key 并发写入 Redis 会打满连接池、阻塞主线程、甚至触发 Redis 的 OOM 或 maxmemory-policy 驱逐。真正安全的预热,必须在零点前至少 5~10 分钟完成,且要避开业务高峰(比如晚 23:45~23:55 是较优窗口)。
常见错误是把预热逻辑写成“零点整执行一个定时任务”,结果任务刚启动,第一批用户请求就涌进来,缓存仍是空的。预热不是“补救”,而是“占位”。
- 用分布式调度器(如 XXL-JOB、ShardingSphere-JDBC 定时任务模块)而非单机
@Scheduled,避免多实例重复写入 - 预热任务应带幂等标识,例如
cache_warmup_20261020,Redis 中用SETNX校验是否已执行 - 避免在预热中调用实时 DB 查询:提前将数据快照导出为 JSON 文件或写入离线 DB 表,预热时只做
SET或MSET
预热数据必须包含 TTL 打散,否则只是把雪崩延后
如果预热时所有 key 都设统一过期时间(比如全设 EX 86400),那它们仍会在 24 小时后同一秒失效,雪崩只是从零点挪到了明天零点。预热 ≠ 简单填充,而是“带防撞设计的填充”。
正确做法是在写入时对每个 key 的 EX 参数加随机偏移:
for item in hot_items:
base_ttl = 86400
jitter = random.randint(0, 1800) # 0–30 分钟
redis.setex(f"daily_rank:{item.id}", base_ttl + jitter, item.json)这个偏移量不能太小( 3600 秒),否则部分 key 过早失效,起不到覆盖零点流量的作用。
预热失败必须有降级兜底,不能静默跳过
线上预热常因网络抖动、Redis 节点临时不可达、序列化失败等原因中断。若任务中途退出却不报警,你根本不知道缓存是否真被填上——直到零点监控告警炸开。
关键动作有三:
- 预热结束后,立即用
redis.eval脚本批量校验核心 key 是否存在且非空,例如return redis.call("EXISTS", KEYS[1]) == 1 and redis.call("STRLEN", KEYS[1]) > 0 - 校验失败的 key 名单必须落库或发 MQ,触发人工介入或自动重试(最多 1 次,避免雪上加霜)
- 业务层需配合启用“懒加载+互斥锁”兜底:即使预热失败,首个请求发现 key 缺失时,由
GETSET或SET key value EX 3600 NX控制回源,防止并发击穿
预热内容要区分冷热,别把低频数据塞进高危时段
双十一零点最危险的是 TOP100 商品、活动页配置、实时榜单这类高 QPS 数据。但很多人一股脑把全量商品都预热进来,既浪费内存,又拖慢预热速度,还可能挤掉真正热点的 LRU 空间。
判断依据只能是最近 24 小时的真实访问日志或 Redis INFO keyspace 中的 keyspace_hits 统计,而不是“我觉得可能火”。实操建议:
- 只预热
QPS > 500且命中率 的 key(说明它容易 miss,风险高) - 对榜单类数据,预热时用“昨日同期值 + 20% 冗余”生成模拟数据,比等 DB 查询更稳
- 完全静态的页面资源(如活动 banner 图片 URL)可直接预热到 CDN,不走 Redis
预热不是拼数量,是拼命中精度。零点前那几分钟,每多写一个无效 key,都在悄悄提高雪崩概率。


















