一、什么是缓存雪崩
当缓存服务器宕机或者在某一个时间段大量缓存集中失效,这时所有的请求都直接查询后端数据库,给数据库造成极大的压力甚至是宕机,从而引起应用服务器雪崩。
二、缓存雪崩的解决方案
对于缓存服务宕机造成的缓存雪崩,可以采用高可用的缓存架构,比如Redis哨兵或者Cluster。
对于大量缓存同时失效造成的缓存雪崩,有以下解决方案:
1、对缓存的过期时间加一个随机数
可以在原有的失效时间基础上增加一个随机数,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
2、加锁排队
在缓存失效后,通过加锁(分布式锁)或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
public class Test {
@Autowired
private RedisTemplate redisTemplate;
public Object get(String key) {
// 先从缓存查询
Object value = redisTemplate.opsForValue().get(key);
// 缓存查询到数据直接返回
if (value != null) {
return value;
} else {
// 缓存没有查询到数据,则进行加锁
if (lock(key)) {
// 获取锁成功后,再次查询缓存,进行双重检查
value = redisTemplate.opsForValue().get(key);
if (value == null) {
// 查询数据库,并设置到缓存中
value = queryDB(key);
redisTemplate.opsForValue().set(key, value);
}
// 释放锁
unlock(key);
return value;
} else {
// 获取锁失败,说明其他线程先获取到锁,再次从缓存查询
return get(key);
}
}
}
// 查询数据库
private Object queryDB(String key) {
return new Object();
}
// 加锁,使用Redis或Zookeeper实现分布式锁
public boolean lock(String key) {
return true;
}
// 释放锁
public void unlock(String key) {
}
}
3、热点数据永不过期
对于热点数据,可以设置为永不过期。
4、服务降级和熔断
如果访问量超过一定阈值,则对后续的请求执行快速失败。如果某些服务不可用,也执行快速失败,防止大量请求阻塞拖垮应用。