Redis——如何解决redis穿透、雪崩、击穿问题

一、查询商品信息的常规代码示例

  • 查询商品信息的常规代码示例
/**
*查询商品信息
*/
public ExpressInfo findByDeliveryOrderId(Long id){
	String key="xz-express:expmess-info:"
	//从 Redis查询物流信息
	Object obj = 	redisTemplate.opsForValue().get( key + id);
	if (obi != null) [
		return (ExpressInfo) obj; 
	}else {
		ExpressInfo expressInfo= expressMapper,selectByDeliveryOrderId(id);//数据库查询	
		if(expressInfo l= nul1){ 
			redisTemplate,opsForValue(),set(key + d,expressInfo,Duration,ofHours(2));
			return expressInfo;
 		}else {
 			throw new clientException("发货单,的物流信息不存在",id);
 		}
	}
}
		

二、缓存击穿

2.1、缓存击穿的理解

  • 高并发时,当一个kev非常热点(类似于爆款)在不停的扛着大并发当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库并设置到缓存中,导致性能下降。
    在这里插入图片描述

2.2、缓存击穿的解决方案

  • 设置缓存永不过期
  • 加锁排队

2.3、解决缓存击穿的代码示例

  • 代码示例

    /**
    *查询商品信息
    */
    @Suppresswarnings("unchecked”)
    public ExpressInfo findByDeliveryOrderId(Long id){
    	String key="xz-express:expmess-info:"
    	//从 Redis查询物流信息
    	Object obj = 	redisTemplate.opsForValue().get( key + id);
    	if (obi == null) {
    		synchronized (this){
    			//进入 synchronized 一定要先再查询一次 Redis,防止上一个抢到锁的线程已经更新过了
    			obj = 	redisTemplate.opsForValue().get( key + id);
    			if(obj != null){
    				return (List<ProductCategory>) obj;
    			}
    			//数据库查询	
    			List<ProductCategory> categorylList = productCategoryMapper.selectProductCategory(id);
    			redisTemplate,opsForValue().set(key,categoryList,Duration.ofHours(2L));
    		}
    		return categorylList ; 
    	}else {
    		return (List<ProductCategory>) obj;
    	}
    }
    

三、缓存雪崩

3.1、缓存雪崩的理解

  • 缓存集中过期,或者缓存服务器宕机,导致大量请求访问数据库,造成数据库瞬间压力过大,宕机。
    在这里插入图片描述

3.2、缓存雪崩的解决方案

3.2.1、缓存集中过期的情况
  • 加锁排队
  • 设置随机失效时间
3.2.2、缓存服务器宕机的情况
  • 提前部署好redis高可用集群(比如哨兵模式)
3.2.3、缓存服务器断电的情况
  • 提前做好灾备(多机房部署)

3.3、解决缓存雪崩(缓存集中过期)的代码示例

  • 代码示例

    /**
    *查询商品信息
    */
    @Suppresswarnings("unchecked”)
    public ExpressInfo findByDeliveryOrderId(Long id){
    	String key="xz-express:expmess-info:"
    	//从 Redis查询物流信息
    	Object obj = 	redisTemplate.opsForValue().get( key + id);
    	if (obi == null) {
    		synchronized (this){
    			//进入 synchronized 一定要先再查询一次 Redis,防止上一个抢到锁的线程已经更新过了
    			obj = 	redisTemplate.opsForValue().get( key + id);
    			if(obj != null){
    				return (List<ProductCategory>) obj;
    			}
    			//数据库查询	
    			List<ProductCategory> categorylList = productCategoryMapper.selectProductCategory(id);
    			//设置随机失效时间
    			Duration expire = DurationofHours(2L).plus(Duration.ofSeconds((Math .random() 100)));
    			redisTemplate,opsForValue().set(key,categoryList,expire);
    		}
    		return categorylList ; 
    	}else {
    		return (List<ProductCategory>) obj;
    	}
    }
    

四、缓存穿透

4.1、缓存穿透的理解

  • 数据库不存在缓存中也不存在,导致每次请求都会去查询数据库,这时的用户很可能是攻击者如发起为id为“-1”的数据或id为特别大(不存在的数据),导致数据库压力过大或宕机。
    在这里插入图片描述

4.2、缓存穿透的解决方案

  • 参数校验
  • 缓存空对象
  • 布隆过滤器

4.3、解决缓存穿透的代码示例

  • 代码示例

    /**
    *查询商品信息
    */
    @Suppresswarnings("unchecked”)
    public ExpressInfo findByDeliveryOrderId(Long id){
    	String key="xz-express:expmess-info:"
    	//从 Redis查询物流信息
    	Object obj = 	redisTemplate.opsForValue().get( key + id);
    	if (obi == null) {
    		synchronized (this){
    			//进入 synchronized 一定要先再查询一次 Redis,防止上一个抢到锁的线程已经更新过了
    			obj = 	redisTemplate.opsForValue().get( key + id);
    			if(obj != null){
    				return (List<ProductCategory>) obj;
    			}
    			//数据库查询	
    			List<ProductCategory> categorylList = productCategoryMapper.selectProductCategory(id);
    			//设置随机失效时间
    			Duration expire = DurationofHours(2L).plus(Duration.ofSeconds((Math .random() 100)));
    			//从数据库中查询出的categoryList不管是否是空,都存到redis中
    			redisTemplate,opsForValue().set(key,categoryList,expire);
    		}
    		return categorylList ; 
    	}else {
    		return (List<ProductCategory>) obj;
    	}
    }
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小志的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值