Redis击穿、穿透、雪崩解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/li1987by/article/details/86703191

Redis击穿、穿透、雪崩解析

面对并发分布式缓存时,Redis可能遇到以下问题
一、击穿
1.问题场景
某个key的数据为热点数据,当缓存过期后,出现大量并发访问该key的情况。造成大量请求该key的访问,落到存储层,直接将存储层压垮。
2.解决办法
一般利用分布式锁–mutex。访问热点数据的线程,如果没有在缓存层获取到数据,只有一个可以获取到一把互斥锁,有资格访问存储层,然后将数据缓存到缓存层。其它需要睡眠等待后重新访问缓存层热点数据。
3.代码示例

 public String get(String key){
      //所有线程优先访问缓存层,获取数据
      String value = redis.get(key);
      //缓存层无该数据
      if(value == null){ 
    	  //设置互斥锁 --mutex
    	  String mutex = key.concat(":mutex");
      	//获取带有过期时间的互斥锁,避免获取互斥锁的线程不能释放,造成后面线程阻塞
	if (redis.setnx(keynx, VALUE, 3 * 60) == VALUE) { 
    	    //代表设置成功
            value = db.get(key);
            redis.set(key, value, expire_secs);
            redis.del(keynx);
        } else {
         //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
         sleep(50);
         //重试
            get(key); 
        }
    } else {
     return value;        
    }
}

或者

private static final String LOCKED_SUCCESS = "OK";
private static final String NX = "NX";
private static final String EXPIRE_TIME = "PX"; 
/*** 获取锁
*
* @param jedis   redis客户端
* @param lockKey    锁的key
* @param uniqueId   请求标识
* @param expireTime 过期时间
* @return 是否获取锁
* *
* /
public static boolean tryDistributedLock(Jedis jedis, String lockKey, String uniqueId, long expireTime) {    
	String result = jedis.set(lockKey, uniqueId, NX, EXPIRE_TIME, expireTime);    
	return LOCKED_SUCCESS.equals(result);
}

二、穿透
1.问题场景
一般是恶意访问数据库中不存在的数据,必然不会存储在缓存中,从而可以直接访问数据层。大量这种请求攻击,就会使数据层挂掉
2.解决办法
1)缓存空值,但是最好设置一个较短的过期时间,如超过5分钟。
2)布隆过滤器
优点:简单,方便集成,空间效率、查询时间远超一般算法
缺点:容错性、不能很好支持大数据(费内存,不能横向扩展)
3.代码示例
1)引用

<dependencies>
<dependency>
 <groupId>com.google.guava</groupId>
 <artifactId>guava</artifactId>
 <version>23.0</version>
</dependency>  
</dependencies> 

初始化存储层数据映射到bitmap

 private static final int capacity = 1000000;
 private static final int key = 999998;
 //第三个参数为出错率
 private static BloomFilter bloomFilter =  BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),capacity ,0.00000008);
@PostConstruct
public void init(){
	List<String> list = orderMapper.query();
	int listSize = list.size();
        for(int i = 0; i < listSize; i++){
       	   bloomFilter.put(list.get(i));
       }

}

查询

public void queryBloom(){	
   int errorCount = 0;
   String temp = "";
   for(int i = 0; i < 10000; i++){
       temp = "test" + i;
   	if(bloomFilter.mightContain(temp)){
   	  errorCount++;
   	}
   }
   System.out.pringln("出错量:" + errorCount);
}

三、雪崩
1.问题场景
主要是大部分的key在同一时间过期,这是这些key有大量的并发访问,将直接访问存储层,使存储层宕掉。
2.解决办法
设置不同的key,不同的过期时间,如设置1~5分钟的随机数。

参考:
Redis分布式锁
Redis -BloomFilter
Redis 击穿 穿透 雪崩

猜你喜欢

转载自blog.csdn.net/li1987by/article/details/86703191