redis击穿,穿透,雪崩以及解决方案
目录
击穿
解决方案一
解决方案二
穿透
解决方案
雪崩
解决方案
击穿
指的是单个key在缓存中查不到,去数据库查询,这样如果并发不大或者数据库数据量不大的话是没有什么问题的。
如果数据库数据量大并且是高并发的情况下那么就可能会造成数据库压力过大而崩溃。
注意: 这里指的是单个key发生高并发。
解决方案一
通过synchronized+双重检查机制:某个key只让一个线程查询,阻塞其它线程。
在同步块中,再次判断检查,保证不存在,才去查DB。
private static final Object lock = new Object();
public String getValue(String key) {
// 先查 redis 中是否有数据
String value = redis.get(key);
// 如果 redis 中没有数据,使用 synchronized 进行加锁
if (StringUtils.isBlank(value)) {
synchronized (lock) {
// 再次查询 redis 中是否有数据,因为第二个线程拿到锁进来的时候value也为空,而此时第一个线程已经写入值了
value = redis.get(key);
// 如果第还是没有数据,此时再查数据库
if (StringUtils.isBlank(value)) {
value = db.query(key);
// 查询到数据库中的数据后,将数据写入到 redis 中
redis.set(key, value, 1000);
}
}
}
return value;
}
缺点: 会阻塞其它线程。
解决方案二
设置value永不过期。
这种方式可以说是最可靠的,最安全的但是占空间,内存消耗大。
穿透
一般是出现这种情况是因为恶意频繁查询才会对系统造成很大的问题,key缓存不存在并且数据库中也不存在,所以每次查询都会查询数据库从而导致数据库崩溃。
解决方案
使用布隆过滤器,它的作⽤就是如果它认为⼀个key不存在,那么这个key就肯定不存在,所以可以在缓存之前加⼀层布隆过滤器来拦截不存在的key。
雪崩
雪崩指的是多个key查询并且出现高并发,缓存中失效或者查不到,然后都去db查询,从而导致db压力突然飙升,从而崩溃。
出现原因:
1)key同时失效
2)redis本身崩溃了
解决方案
1、在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。(跟击穿的第一个方案类似,但是这样是避免不了其它key去查数据库,只能减少查询的次数)。
2、可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存。
3、不同的key,设置不同的过期时间,具体值可以根据业务决定,让缓存失效的时间点尽量均匀。
4、做二级缓存,或者双缓存策略。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。(这种方式复杂点)。