缓存预热策略:让缓存”热”起来

缓存预热策略:让缓存”热”起来

什么是缓存预热

缓存预热(Cache Warming / Pre-heating)是指系统上线或重启后,在正式对外提供服务之前,主动将热点数据加载到缓存中的过程。目的是避免缓存刚启动时”冷启动”状态下大量请求穿透到数据库。

为什么需要缓存预热

缓存服务刚启动时是空的(或者 Redis 重启、集群扩容、缓存大面积失效后),此时没有任何数据在缓存中。如果直接开放流量:

  1. 缓存雪崩:大量请求同时穿透到数据库,导致数据库被打垮
  2. 服务超时:数据库扛不住压力,服务响应变慢甚至不可用
  3. 慢启动现象:上线后的前几分钟请求延迟明显偏高

缓存预热就是为了消除这个”冷启动”窗口。

常用预热策略

1. 定时预热(离线脚本)

系统上线或低峰期,通过脚本批量查询数据库,将热点数据写入缓存。

# 预热脚本示例
redis-cli -h localhost -p 6379 MSET \
  user:1001 "$(cat data/user_1001.json)" \
  user:1002 "$(cat data/user_1002.json)" \
  product:2001 "$(cat data/product_2001.json)"

优点:实现简单,可以在上线前单独执行
缺点:数据新鲜度依赖脚本更新的时机

2. 懒加载预热(启动时加载)

应用启动时,在 @PostConstruct 或 ApplicationRunner 中执行预热逻辑:

@Component
public class CacheWarmer {
    @Autowired private RedisTemplate redis;
    @Autowired private HotDataService hotDataService;

    @PostConstruct
    public void warmUp() {
        // 加载 Top 10000 热点商品
        List<HotProduct> topProducts = hotDataService.getTopProducts(10000);
        topProducts.parallelStream().forEach(p -> {
            redis.opsForValue().set("product:" + p.getId(), 
                JSON.toJSONString(p), 30, TimeUnit.MINUTES);
        });
        log.info("缓存预热完成,共加载 {} 条热点数据", topProducts.size());
    }
}

优点:自动化,重启即预热
缺点:增加启动时间,预热完成前服务不应接受流量

3. 流量驱动的渐进式预热

不主动加载,而是在缓存未命中时,通过限流和互斥锁机制控制穿透流量:

public String getWithWarmUp(String key) {
    String value = redis.opsForValue().get(key);
    if (value != null) return value;

    // 使用分布式锁,只有一个线程回源
    String lockKey = "lock:" + key;
    if (redis.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS)) {
        try {
            value = loadFromDB(key);
            redis.opsForValue().set(key, value, 30, TimeUnit.MINUTES);
        } finally {
            redis.delete(lockKey);
        }
    } else {
        // 等待其他线程加载
        Thread.sleep(100);
        return redis.opsForValue().get(key);
    }
    return value;
}

优点:不需要提前规划热点数据,自然适应流量变化
缺点:预热阶段仍然会有少量请求穿透

4. 读写穿透预热(缓存预热服务)

使用一个独立的数据同步服务,监听数据库变更并实时同步到缓存。适用于数据实时性要求高的场景,比如使用 Canal 监听 MySQL binlog:

MySQL → Canal → Kafka → 预热消费者 → Redis

优点:数据实时同步,缓存与数据库几乎一致
缺点:架构复杂,引入额外中间件

预热策略的选择

策略 适用场景 复杂度
离线脚本 静态数据、配置类数据
启动加载 热点列表明确的场景
流量驱动 热点不确定、长尾流量
读写穿透 强一致性要求、实时性强

最佳实践

  1. 分优先级预热:核心数据先预热,非核心延后
  2. 错开过期时间:预热时设置不同的 TTL,避免集中失效
  3. 监控预热进度:记录预热耗时、加载条数、缓存命中率提升效果
  4. 预热不要压垮 DB:控制并发度,特别是启动加载时
  5. 结合流量预估:根据历史 QPS 预估预热数据量级

面试要点

  • 说清缓存预热的本质是把冷缓存变热,防止启动期间的穿透
  • 能举出实际预热方案,并说出优缺点
  • 最好能提到”预热时间要控制在优雅停机窗口内”
  • 对大型系统可以提到”全量预热 + 增量同步”的组合策略
© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容