Redis 缓存击穿问题及解决方案
# 什么是缓存击穿
缓存击穿是 “一个热点 Key(如热门商品详情、热门文章)过期时,大量并发请求同时穿透缓存,直接查询数据库,导致数据库瞬间压力骤增” 的问题。与缓存穿透(查询不存在的 Key)不同,击穿的 Key 是真实存在的,只是恰好过期。
# 解决方案
1. 热点 Key 永不过期:
- 对热点 Key 不设置过期时间(
expire),避免 Key 过期导致的击穿; - 同时在后台启动定时任务,定期更新热点 Key 的 value(如每 10 分钟更新一次热门商品库存),确保数据一致性。
- 优点:实现简单,无并发问题;缺点:占用 Redis 内存(若热点 Key 过多),需确保定时任务可靠。
- 对热点 Key 不设置过期时间(
2. 互斥锁(分布式锁):
当请求查询缓存时,若 Key 不存在,先通过 Redis 的
setNx(set if not exists)获取分布式锁,只有获取到锁的请求才能查询数据库,查询后更新缓存,其他请求则等待(如自旋重试或休眠),直到缓存更新完成。示例(伪代码):
java 运行
public Object getHotData(String key) { // 1. 查询缓存 Object data = redis.get(key); if (data != null) return data; // 2. 获取分布式锁 boolean lock = redis.setNx("lock:" + key, "1", 5); // 锁过期时间5秒,避免死锁 if (lock) { try { // 3. 再次查缓存(防止其他请求已更新) data = redis.get(key); if (data != null) return data; // 4. 查数据库 data = db.query(key); // 5. 更新缓存(设置过期时间) redis.set(key, data, 300); // 5分钟过期 return data; } finally { // 6. 释放锁 redis.delete("lock:" + key); } } else { // 7. 未获取到锁,重试(休眠100ms后再次查询) Thread.sleep(100); return getHotData(key); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26优点:确保只有一个请求查数据库,保护数据库;缺点:存在锁竞争,请求可能等待,影响接口响应时间。
3. 预热缓存:
- 在系统上线前或流量高峰来临前(如电商大促),通过脚本或后台任务将热点 Key 提前加载到 Redis,并设置合理的过期时间;
- 例如:大促前 1 小时,将 Top1000 热门商品的详情数据加载到 Redis,过期时间设为大促结束后。
- 优点:从源头避免 Key 过期导致的击穿;缺点:需提前识别热点 Key,对未知热点 Key 无效。
上次更新: 12/30/2025