大数跨境
0
0

字节二面:Redis缓存预热,该如何实现?

字节二面:Redis缓存预热,该如何实现? Java技术图谱
2025-12-02
0

面 Redis 时,面试官八成不会问“缓存怎么用”这种基础问题,而是会来一句:

“如果我现在一个接口 QPS 8k,缓存还没预热,你怎么避免所有请求瞬间把数据库打爆?”

第一次被问到这题的时候,我愣了半秒,因为缓存预热这东西吧……大家都知道要“提前把热门数据塞到缓存里”,但真的让你讲方案、落代码、说风险,能讲完整的人其实并不多。

下面我把我自己在面试和实际项目里的经验整理成一个完整方案,你可以按场景拆着记。

为什么要预热?不预热会发生什么?

你可以想象一个电商首页,刚上线还没访问过。Redis 里啥都没有,这时候流量一来:

  1. 用户请求 → 查 Redis,发现 miss
  2. 全量请求都打到 DB
  3. DB 顶不住,直接变“下单失败,请稍后再试”

只要缓存 hit 率稍微低一点,都会把数据库带走。所以预热的本质就是:把预期最热的数据提前灌进 Redis,让冷启动也能扛住高流量。

常见的缓存预热方案(面试官最爱问)

这里有 4 套方案,你按场景记就行。

1. 应用启动时预热(最常见)

项目启动的时候,自动把热门数据加载进 Redis。

比如一些固定的配置、首页推荐列表、排行榜、类目树等。

Java 伪代码如下:

@Component
publicclass CacheWarmUpRunner implements ApplicationRunner {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private GoodsService goodsService;

    @Override
    public void run(ApplicationArguments args) {
        // 加载热门商品
        List<Goods> hotList = goodsService.queryHotGoods();

        for (Goods g : hotList) {
            redisTemplate.opsForValue().set("goods:" + g.getId(), g, Duration.ofMinutes(30));
        }
    }
}

优点:简单、可控 缺点:重启才会更新,灵活性一般

2. 发布前手动脚本预热(大厂常用)

像字节、阿里这类流量巨大的场景,经常会在 发布前 通过脚本预热。

比如一个 release 流程里,会有“数据预热阶段”,脚本先跑一轮:

public class WarmUpScript {

    public static void main(String[] args) {
        RedisTemplate<String, Object> redis = SpringUtil.getBean(RedisTemplate.class);
        CategoryService categoryService = SpringUtil.getBean(CategoryService.class);

        List<Category> categories = categoryService.loadAll();
        redis.opsForValue().set("categories", categories, Duration.ofHours(2));
    }
}

特点:

  • 不依赖应用启动
  • 可以预热多个 Redis 集群
  • 自动化程度高

3. 定时任务周期预热(适合数据变化不大)

比如排行榜、推荐列表这样的数据,它并不是实时变动,可以用定时任务预热。

@Scheduled(fixedRate = 5 * 60 * 1000)
public void refreshTopListCache() {
    List<TopItem> list = service.loadTopItems();
    redisTemplate.opsForValue().set("top:list", list, Duration.ofMinutes(10));
}

优点:

  • 让缓存长期保持“半热”状态
  • 避免突然过期导致缓存雪崩

4. 双缓存机制(解决过期瞬间的抖动)

这招是字节、快手常用的。

做法:

  1. 缓存 A 设置 短过期时间

  2. 缓存 B 设置 长过期时间

  3. 每次取缓存顺序是:

    • 先读 A → 如果 A 没值,再读 B
    • 同时异步更新 A

代码如下:

public Object getWithDoubleCache(String key) {
    Object a = redis.opsForValue().get("A:" + key);
    if (a != nullreturn a;

    Object b = redis.opsForValue().get("B:" + key);
    if (b != null) {
        // 异步刷新 A
        CompletableFuture.runAsync(() -> 
            redis.opsForValue().set("A:" + key, b, Duration.ofMinutes(5))
        );
        return b;
    }

    // 都没则查 DB
    Object db = loadFromDb(key);
    redis.opsForValue().set("A:" + key, db, Duration.ofMinutes(5));
    redis.opsForValue().set("B:" + key, db, Duration.ofHours(1));
    return db;
}

优点:防止缓存击穿、避免热点 Key 过期瞬间压垮 DB 缺点:实现较复杂

面试官会追问:预热从哪里拿“热门数据”?

你可以从 3 个维度回答:

① 业务固有热门

比如:

  • 首页 Banner
  • 类目树
  • 排行榜
  • 默认配置

② 历史数据统计

例如:

  • 最近 7 天最热商品
  • 高频接口的 Top N 参数
  • 热门榜单

③ 大促活动运营侧推送

比如运营提前告诉你:

“这 1000 件商品会被大量访问”

你就可以提前加载。

这样回答,面试官会立刻觉得你有真实经验。

面试官高级追问:预热失败了怎么办?

你必须提出“兜底策略”,否则方案不完整。

常见兜底:

  1. 热点 Key 使用互斥锁避免击穿
String lockKey = "lock:goods:" + id;
Boolean locked = redis.setIfAbsent(lockKey, 110, TimeUnit.SECONDS);

if (locked) {
    Goods goods = db.query(id);
    redis.set("goods:" + id, goods, 30, TimeUnit.MINUTES);
    redis.delete(lockKey);
else {
    // 让请求等待或直接返回兜底数据
}
  1. 大量 Key 同时过期 → 设置过期时间随机化
int expire = 300 + new Random().nextInt(60);
redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
  1. 预热时 Redis 崩了 → 自动切到 DB 降级逻辑并限流

真实项目中的预热套路(面试必加分)

可以这样讲:

“我们当时做活动页,页面上有 200+ 个商品卡片。上线前运维平台会自动跑一遍 Redis 预热,把这些商品、库存、销量都提前放进去。

另外我们还做了一个监控脚本,一旦某个 key 命中率下降,就自动触发预热任务,保证整个活动期间缓存一直保持热状态。”

听起来是不是非常真实?面试官也最喜欢这种实战式回答。

如果你要在面试中 30 秒总结,可以这样说:

“缓存预热主要有 3 个目的:提高命中率、避免缓存冷启动、保护数据库。

方案常见有:应用启动预热、发布脚本预热、定时任务周期预热、双缓存机制。

数据来源可以是业务固有热门、历史统计、运营提前推送。

而且预热方案要配合随机过期时间、互斥锁、限流等兜底措施,才能避免雪崩和击穿。”

面试官听完一般会点头:“OK,很全面。”

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html


🔥东哥私藏精品🔥


东哥作为一名老码农,整理了全网最全《Java高级架构师资料合集》。总量高达650GB点击下方公众号回复关键字java 全部免费领取

【声明】内容源于网络
0
0
Java技术图谱
回复 java,领取Java面试题。分享AI编程,AI工具,Java教程,Java下载,Java技术栈,Java源码,Java课程,Java技术架构,Java基础教程,Java高级教程,idea教程,Java架构师,Java微服务架构。
内容 1111
粉丝 0
Java技术图谱 回复 java,领取Java面试题。分享AI编程,AI工具,Java教程,Java下载,Java技术栈,Java源码,Java课程,Java技术架构,Java基础教程,Java高级教程,idea教程,Java架构师,Java微服务架构。
总阅读56
粉丝0
内容1.1k