面 Redis 时,面试官八成不会问“缓存怎么用”这种基础问题,而是会来一句:
“如果我现在一个接口 QPS 8k,缓存还没预热,你怎么避免所有请求瞬间把数据库打爆?”
第一次被问到这题的时候,我愣了半秒,因为缓存预热这东西吧……大家都知道要“提前把热门数据塞到缓存里”,但真的让你讲方案、落代码、说风险,能讲完整的人其实并不多。
下面我把我自己在面试和实际项目里的经验整理成一个完整方案,你可以按场景拆着记。
为什么要预热?不预热会发生什么?
你可以想象一个电商首页,刚上线还没访问过。Redis 里啥都没有,这时候流量一来:
-
用户请求 → 查 Redis,发现 miss -
全量请求都打到 DB -
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. 双缓存机制(解决过期瞬间的抖动)
这招是字节、快手常用的。
做法:
-
缓存 A 设置 短过期时间
-
缓存 B 设置 长过期时间
-
每次取缓存顺序是:
-
先读 A → 如果 A 没值,再读 B -
同时异步更新 A
代码如下:
public Object getWithDoubleCache(String key) {
Object a = redis.opsForValue().get("A:" + key);
if (a != null) return 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 件商品会被大量访问”
你就可以提前加载。
这样回答,面试官会立刻觉得你有真实经验。
面试官高级追问:预热失败了怎么办?
你必须提出“兜底策略”,否则方案不完整。
常见兜底:
-
热点 Key 使用互斥锁避免击穿
String lockKey = "lock:goods:" + id;
Boolean locked = redis.setIfAbsent(lockKey, 1, 10, TimeUnit.SECONDS);
if (locked) {
Goods goods = db.query(id);
redis.set("goods:" + id, goods, 30, TimeUnit.MINUTES);
redis.delete(lockKey);
} else {
// 让请求等待或直接返回兜底数据
}
-
大量 Key 同时过期 → 设置过期时间随机化
int expire = 300 + new Random().nextInt(60);
redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
-
预热时 Redis 崩了 → 自动切到 DB 降级逻辑并限流
真实项目中的预热套路(面试必加分)
可以这样讲:
“我们当时做活动页,页面上有 200+ 个商品卡片。上线前运维平台会自动跑一遍 Redis 预热,把这些商品、库存、销量都提前放进去。
另外我们还做了一个监控脚本,一旦某个 key 命中率下降,就自动触发预热任务,保证整个活动期间缓存一直保持热状态。”
听起来是不是非常真实?面试官也最喜欢这种实战式回答。
如果你要在面试中 30 秒总结,可以这样说:
“缓存预热主要有 3 个目的:提高命中率、避免缓存冷启动、保护数据库。
方案常见有:应用启动预热、发布脚本预热、定时任务周期预热、双缓存机制。
数据来源可以是业务固有热门、历史统计、运营提前推送。
而且预热方案要配合随机过期时间、互斥锁、限流等兜底措施,才能避免雪崩和击穿。”
面试官听完一般会点头:“OK,很全面。”
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
🔥东哥私藏精品🔥
东哥作为一名老码农,整理了全网最全《Java高级架构师资料合集》。总量高达650GB。点击下方公众号回复关键字java 全部免费领取

