Redis缓存查询(防止缓存穿透)原因以及解决方法


前言

缓存击穿产生的场景?

为了解决内存与磁盘速度不匹配的问题,就要用到缓存。将热点数据存放在redis中随用随取,不仅可以降低连接到数据库的请求,避免数据库挂掉;还可以减少频繁重复的复杂逻辑结果。需要注意的是,无论是击穿、穿透与雪崩,都是在高并发前提下。

什么是缓存击穿? 缓存击穿就是在处于集中式高并发访问的情况下,当某个热点 key 在失效的瞬间,大量的请求在缓存中获取不到。瞬间击穿了缓存,所有请求直接打到数据库,就像是在一道屏障上击穿了一个洞,单一使用数据库来保存数据的系统会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪,最终导致服务宕机的严重生产问题。 为了克服上述的问题,项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供一定的持久化功能。 redis技术就是NoSQL技术中的一种,但是引入redis又有可能出现缓存穿透,缓存击穿,缓存雪崩等问题。

示意图


    缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。 缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。 缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

解决办法

在方法内加入同步代码块,如果从缓存中无法读取,限制访问,只允许一个请求进入方法,通过数据库查询数据,将数据卡在服务端,防止瞬时访问数据库压力 下面只讲一种数据类型,大致思路很好理解
@Autowired
private StringRedisTemplate redisTemplate;

@Autowired
private UserMapper userMapper;

public <?> getResourceByConsumer(String consumerId){
          
   
   try {
          
   
       if(redisUtil.hasKey(consumerId)){
          
   
           String demoValue= redisTemplate.opsForValue().get(demoKey);
           return demoValue;
       }else {
          
   
           synchronized (this){
          
   
               String message=userMapper.getMessage(consumerId);
               redisTemplate.opsForValue().set("message-"+consumerId,message);
               return message;
           }
       }catch (Exception e){
          
   
       	 
  	   }
}

经验分享 程序员 微信小程序 职场和发展