预热脚本失效主因是过期时间未加随机偏移导致集体过期;需为每个key设置1800–3600秒基础过期时间并叠加±300–600秒随机值,避免整点雪崩。

预热脚本跑完就失效?过期时间没加随机偏移是主因
预热后刚上线就雪崩,大概率不是没预热,而是所有 setex 设置的过期时间完全一致。比如统一设成 3600 秒,一小时整点集体过期,数据库瞬间被压垮。
必须给每个 key 加上随机偏移量,把失效时间打散:
- 基础过期时间建议设为 30–60 分钟(
1800–3600),别贪长 - 随机范围至少取 ±5–10 分钟(
300–600),避免集中在某几分钟内 - 别用
time.time() + base这种写法——它不解决批量 key 同时过期问题;重点是每个 key 的expire值要独立生成
import random
pipe.setex(key, 3600 + random.randint(0, 600), json.dumps(value))
用 pipeline 预热却卡住或报错?检查 Redis 连接与 DB 选择
预热脚本在本地跑通,部署到生产就超时或连不上,90% 是连接配置没对齐:
redis.Redis(host='localhost', port=6379, db=0)在容器或云环境里基本等于写死失败——localhost指的是容器自己,不是宿主机或 Redis 实例- 确认实际 Redis 地址、端口、密码(
password参数)、DB 编号是否和线上配置一致,尤其注意db=0是否被其他服务占用 - 如果用了哨兵或集群,
redis.Redis不支持,得换redis.sentinel.Sentinel或redis.cluster.RedisCluster
预热数据明明进了 Redis,但请求还是打到 DB?缓存键名不一致是隐形杀手
预热脚本里用 "homepage_banner",而业务代码拼的是 f"banner:{env}:v2",结果就是“预了等于没预”。这种错不会报错,只会静默失效。
- 把预热脚本里的 key 定义抽成常量模块(如
cache_keys.py),业务代码和预热脚本共用同一份 - 上线前用
redis-cli --scan --pattern "banner*"手动扫一遍,确认 key 真的存在且格式匹配 - 避免在预热时用
json.dumps但业务层用pickle解析,序列化方式必须严格一致
系统启动即预热,但 DB 尚未就绪导致失败?加重试和健康检查
微服务启动顺序不可控:应用进程起来了,Redis 连上了,但 MySQL 还在初始化连接池,这时预热调用 get_top_products() 直接抛异常,整个预热中断,缓存空空如也。
- 预热函数内部对每个数据源调用加 try/except,单个失败不影响其他 key 加载
- 关键依赖(如 DB)启动后主动发一次健康探测(如
SELECT 1),成功后再触发预热主逻辑 - 不要把预热塞进
__init__.py或 Django 的ready()—— 它们没超时控制;单独起一个带 timeout 的同步任务更稳妥