1.什么是缓存击穿?怎么解决?
缓存击穿是指在高并发场景下,某个热点key突然过期失效,此时大量请求同时访问这个已经过期的key,导致所有请求都直接打到数据库上,造成数据库瞬时压力过大甚至崩溃的情况。
解决方案
1. 互斥锁(Mutex Lock)
-
当缓存失效时,不是所有请求都去查询数据库
-
第一个请求获取锁并查询数据库,其他请求等待
-
数据库查询完成后更新缓存,后续请求直接从缓存获取
public Object getData(String key) {
Object value = redis.get(key);
if (value == null) {
if (redis.setnx(key_mutex, 1, 60)) { // 获取锁
value = db.get(key); // 查询数据库
redis.set(key, value); // 更新缓存
redis.del(key_mutex); // 释放锁
} else {
Thread.sleep(50); // 等待
return getData(key); // 重试
}
}
return value;
}
2. 永不过期策略
-
对热点key设置永不过期(或逻辑过期)
-
后台异步更新缓存数据
-
需要额外的维护逻辑来保证数据一致性
3. 提前续期
-
在key即将过期前,提前异步刷新缓存
-
避免在过期时刻大量请求涌入
4. 缓存预热
-
系统启动时或高峰来临前,预先加载热点数据到缓存
-
特别适合可预测的热点场景
5. 双缓存策略
-
设置两级缓存:一级缓存(短期)和二级缓存(长期)
-
一级缓存失效时从二级缓存获取,同时异步更新一级缓存
最佳实践建议
-
对于极热点数据,优先考虑永不过期+后台刷新策略
-
一般热点数据使用互斥锁方案,注意锁的粒度要小
-
结合业务特点选择合适的方案,可能需要多种方案组合使用
-
监控热点key,对高频访问的数据特殊处理
2.什么是缓存雪崩?怎么解决?
缓存雪崩是指在同一时间段内,大量缓存key同时失效或缓存服务宕机,导致所有请求直接打到数据库上,造成数据库瞬时压力激增甚至崩溃的现象。
1. 过期时间随机化
-
避免大量key同时过期
-
在基础过期时间上增加随机值(如1-5分钟的随机数)
// 设置缓存时添加随机过期时间
int expireTime = 3600 + new Random().nextInt(300); // 3600-3900秒
redis.set(key, value, expireTime);