redis缓存常见问题及解决方案

1、缓存穿透

缓存穿透是指查询一个一定不存在的数据(数据库中也没有这个数据),由于缓存不命中,从存储层也查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

解决方案:布隆过滤器
它实际上是由一个很长的二进制数组(或者也叫bitmap)和一系列哈希函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中。如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。链表,树等等数据结构都是这种思路. 但是随着集合中元素的增加,我们需要的存储空间越来越大,检索速度也越来越慢。
在这里插入图片描述
以上图为例,具体的操作流程:假设集合里面有3个元素{x, y, z},哈希函数的个数为3。首先将位数组进行初始化,将里面每个位都设置位0。对于集合里面的每一个元素,将元素依次通过3个哈希函数进行映射,每次映射都会产生一个哈希值,这个值对应位数组上面的一个点,然后将位数组对应的位置标记为1。查询W元素是否存在集合中的时候,同样的方法将W通过哈希映射到位数组上的3个点。如果3个点的其中有一个点不为1,则可以判断该元素一定不存在集合中。反之,如果3个点都为1,则该元素可能存在集合中。注意:此处不能判断该元素是否一定存在集合中,可能存在一定的误判率。可以从图中可以看到:假设某个元素通过映射对应下标为4,5,6这3个点。虽然这3个点都为1,但是很明显这3个点是不同元素经过哈希得到的位置,因此这种情况说明元素虽然不在集合中,也可能对应的都是1,这是误判率存在的原因。

2、缓存击穿和分布式锁

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
解决方案
1、设置热点数据永不过期
2、加互斥锁

Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。如果key已经存在,相当于此命令作废。当Setnx命令执行成功,说明当前应用抢到了锁。
在这里插入图片描述
在当前场景下,假设应用1抢到了锁,那么应用2则被阻塞,或者在不断尝试获取锁的过程。但是,此时有个问题。如果应用1挂了,lock这个key没有被删掉一直存在,那么会导致应用2一直获取不到锁,这就导致了死锁
解决方案:设值key的时候加上过期时间
在这里插入图片描述
但是可能会出现另外一个问题,假设减库存这个操作比较耗时,耗费了3s,那么会导致,应用1还在减库存的时候,就已经释放了锁,应用2抢到了锁,也进行减库存操作,此时分布式锁就已经失去了作用了,出现两个应用同时减库存的情况。
解决方案:setnx加锁的时候,创建一个线程隔一段时间给锁续期
在这里插入图片描述
ttl命令查看key生存时间,如果key不存在,返回-2
创建一个线程每隔1s给key续期1s,如果key被删掉了,也就不会在续期了。注意给这个线程设置成守护线程。这样,即使应用1挂掉了,那这个守护线程也就结束了,不在续期,所以不会出现上面死锁的情况。

public static String getData(String key) throws Exception{

    //先走布隆过滤器
	boolean bloomExist = bloomFilter.isExist(key);
    if(!bloomExist){
         return "查询无果";
    }

    //从缓存钟读取数据
	String result = getDataFromRedis(key);
	//缓存中存在数据
	if(!StringUtils.isEmpty(result)){
	    //正常返回数据
		return result;
	}
	try{
	    redisLock.lock();
		//先在查一次缓存,这个时候缓存中可能已经有数据了
		result = getDataFromRedis(key);
		if(!StringUtils.isEmpty(result)){
	        //正常返回数据
		    return result;
	    }
		//去数据库取数据
		result = getDataFromMysql(key);
		if(!StringUtils.isEmpty(result)){
		    //设置缓存
			setDataToCache(key,result);
	        //正常返回数据
		    return result;
	    }
		return "数据库无结果";
	}finally{
	    //释放锁
		redisLock.unlock();
	}
}

缓存雪崩
缓存雪崩是指缓存中数据大批量到过期时间。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
1、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2、如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值