Redis缓存穿透、缓存雪崩、缓存击穿

soyo 2020-05-11

缓存穿透

缓存穿透:用户恶意模拟请求很多缓存中不存在的数据,由于缓存中没有,数据库中也没有,大量的请求就会直接落在了数据库上,导致数据库出现异常

解决办法:

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;
}

相关推荐