Redis缓存穿透、缓存雪崩、缓存击穿
缓存穿透
缓存穿透:用户恶意模拟请求很多缓存中不存在的数据,由于缓存中没有,数据库中也没有,大量的请求就会直接落在了数据库上,导致数据库出现异常
解决办法:
1.对接口进行限流 ,单个用户每分钟请求多少次
2.如果查询的数据为空,那么设置一个默认值到缓存中,这样第二次请求就会落到缓存中,而不会落到数据库;
//伪代码
public Object get(String key){
String value = redis.get(key);
if(value==null || "".equals(value)){
//如果缓存为空,查询数据库
value = mysql.get(key);
//如果数据库查询不到数据,也放入缓存,可以设置一个过期时间
if(value==null || "".equals(value)){
redis.set(key,value,3000);
}else{
redis.set(key,value);
}
}else{
//如果缓存存在,直接返回
value = JsonUtils.toObject(value);
}
return value;
}
缓存雪崩
缓存雪崩是指设置缓存时候设置了相同时间,缓存某一时刻全部失效,导致请求全部转发到数据库,数据库顺间压力过程导致雪崩(崩溃)
解决方案:
1.设置热点数据永不过期
2.缓存数据的过期时间设置为随机 ,这样过期的重复率就会降低
缓存击穿
缓存击穿是缓存中没有数据但是数据库中有数据(一般是由于key过期导致),这时由于并发用户特别多,同时读取缓存没有读取到数据,同时去数据库读取数据 ,导致数据库压力瞬间增大
缓存击穿与缓存雪崩的区别是 击穿是针对某一个key,雪崩是针对很多key
解决方案:
1.对于热点的数据设置为永不过期
2.使用互斥锁,通常使用redis的setnx
public String get(String key){
//从缓存中获取数据
String value = redis.get(key);
//如果缓存中没有数据
if(value == null){
//不要直接去数据库里取,设置一个锁,如果有一个人获取到了锁就去查询数据库然后添加缓存
//这里给锁设置三分钟避免del失败,下次缓存过期一直不能去数据库里取
if(redis.setnx(key_ex,1,3*60) == 1){
redis.set(key,value,expire);
redis.del(key_ex);
}else{
//没有获取到锁的用户,说明缓存中已经有人添加获取,直接获取即可
//休息50毫秒保险一点,因为redis添加需要时间
sleep(100);
get(key);
}
}
//缓存中有数据直接返回
return value;
}

浙公网安备 33010602011771号