缓存预热有哪些遵守原则?有哪些常见方案?
本文仅抛砖引玉的列举一些常见方案,更详细的实现暂略,未来有机会再深入。
一、预热的本质
缓存预热的核心本质是:在业务流量到来之前,提前将热点 / 核心业务数据加载到缓存层(分布式缓存 + 本地缓存),从根源上避免缓存冷启动的请求直接打库,是解决缓存击穿、雪崩、穿透的前置核心手段,同时能大幅提升业务接口的响应速度。
二、预热原则
- 按优先级进行预热:先预热核心热点数据,后全量非核心数据;先高频访问数据,后低频冷数据,杜绝无差别全量预热浪费内存。
- 选择合适的预热时机:对于热点活动、大促等情况,预热操作必须预留足够的校验和故障时间,同时需要避开业务高峰期。
- 资源合理控制:当预热的数据量较大时,必须分批、限速,进行“灰度预热”,实时观察观察数据库、缓存的负载,绝对不能一次性全量扫库,避免把数据库 / 缓存的带宽、CPU 打满,引发意外故障。在多实例环境下需要考虑分布式锁避免重复扫库。
- 一致性问题:如果在项目运行期间进行运热,预热的数据必须是数据库的最新快照,预热期间若有数据更新,必须同步更新缓存,避免预热旧数据导致脏读。
- 预热前的评估:提前计算预热数据的内存占用,确保 Redis 的可用内存足够,避免预热导致缓存 OOM、key 被强制淘汰。
- 预热后的校验:预热完成后必须做结果校验(key 数量、数据完整性、过期时间),不能预热后直接放流量。
三、预热方式
方式一:数据量不大时,可以写入项目启动流程中,自动加载。
该方式实现简单,适用于服务重启 / 新服务上线后的冷启动场景,不适合大数据量会延长服务启动时间,同时在多实例部署时,需要增加分布式锁避免重复扫库。
在 Java 中的实现:@PostConstruct 注解、Spring 的 CommandLineRunner / ApplicationRunner 等。
在 Python 等其他语言:服务初始化完成后的钩子函数。
方式二:定时任务异步预热
通过分布式定时任务组件,按固定周期异步执行缓存更新 / 预热逻辑,刷新缓存中的数据。
该方式适用于非实时性要求的全量数据预热,任务执行时间必须选在业务低峰期,在分布式环境下如果采用应用级定时任务,需通过分布式锁避免重复执行。数据量大时必须分批处理,预热完成后,最好要做数据校验。
方式三:基于用户行为的动态热点预热
通过实时数据分析 / 应用层统计,自动识别热点数据,触发自动预热。一般有多种统计方式:
- 在 API 网关统计热点接口 / 参数,提前将对应数据预加载到缓存。
- 通过本地缓存组件(Caffeine、Guava Cache)的热点淘汰算法(如 Window-TinyLFU),自动识别高频访问数据,加载到本地缓存,同时同步到分布式缓存。
- 通过 Flink / Spark Streaming 实时消费网关 / 应用的访问日志,统计 TopN 热点 Key(如访问量前 1000 的商品、短视频、新闻),自动将数据写入缓存。
方式四:编写一个预热机制,进行手工操作
针对可预知的流量高峰,人工定向将指定的热点数据提前写入缓存。适用于可预知的流量高峰场景。实现方式有:
- 后台可视化页面操作
在运营后台配置预热页面,点击按钮触发预热任务,支持预览、校验、撤销。 - 脚本批量预热
用 Python / Shell / Java 写临时脚本,读取数据库中指定的活动数据,批量写入 Redis。 - 压测时预热
压测时,同步完成热点数据预热,同时验证缓存承载能力。
四、特殊场景下的预热方式
场景一:故障恢复后的快速预热
该场景主要针对缓存服务器宕机,数据容灾,迁移等容灾场景,避免故障恢复后全量数据请求直接给数据库施压,这种场景需要提前制定容灾恢复计划,主要有以下几种方式:
- 借助 Redis 持久化恢复机制
提前开启 Redis 的 RDB + AOF 混合持久化,集群故障恢复后,自动从持久化文件加载预热数据。 - 借助脚本进行同步
故障恢复后,用分布式脚本快速分批将数据库的核心数据写入缓存,优先恢复核心业务数据。 - 通过双写机制
业务代码中实现更新数据库时同步写缓存的双写逻辑,通过正常的业务读写,逐步恢复全量缓存数据。
场景二:超大并发且需要超低延迟的核心链路场景
对于这种情况就采取多级缓存分层预热策略,通过本地缓存预热核心的 TopN 热点数据,Redis 作为核心缓存层,可以进行全量业务数据预热(注意要按优先级分批、限速),超高并发的秒杀数据直接到本地缓存,完全不经过 Redis,扛住峰值流量。
五、组合拳
- 冷启动兜底:服务启动时用钩子函数预热核心字典、系统配置等数据;
- 日常运维:每天业务低谷用类似 xxl-job 的定时任务,分批全量预热一些基础数据,更新缓存;
- 动态热点:用 Flink 实时分析用户访问日志,识别 TopN 热点商品,自动预热到缓存,应对突发流量;
- 特殊时候:例如什么大活动、大促什么的。提前 24 小时人工定向预热,灰度执行 + 全量校验,热点 key 根据业务情况设置永不过期;
- 容灾恢复:提前制定故障恢复预热预案,Redis 故障恢复后,优先预热核心数据,配合双写逐步恢复全量缓存;
- 兜底补充:一些用户的个性化数据、长尾冷数据之类的,用懒加载加分布式互斥锁,避免缓存击穿;