乐趣区

关于java:谈谈redis缓存击穿透和缓存击穿的区别以及它们所引起的雪崩效应

面试经验

在很长的一段时间里,我认为缓存击穿和缓存穿透是一个货色,直到最近去腾讯面试,面试官问我缓存击穿和穿透的区别;我答复它俩是一样的,面试官马上抬起头用他那修长的单眼皮眼睛瞪着我说:“你确定吗?”,最初面试揭示我,既然有不同的名字,那他们必定就是不一样的,也就是说缓存击穿和缓存穿透不是一个货色;

那么明天咱们就看看这俩玩意的区别,以及它们引发的结果;

在我的项目中退出缓存

个别状况下,咱们会把热点数据放到缓存中,比方罕用的字典、用户信息、订单详情等等;也就是说,当我的项目启动后,先将热点数据加载到 redis 中,当前须要数据时就不必每次都去数据库查问了,这样一来,既缩小了数据库的压力,也晋升了访问速度,堪称是一举多得呀!

缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户一直发动申请,如发动为 id 为“-1”的数据或 id 为特地大不存在的数据。这时的用户很可能是攻击者,攻打会导致数据库压力过大。

解决方案:

  1. 接口层减少校验,如用户鉴权校验,id 做根底校验,id<= 0 的间接拦挡;
  2. 从缓存取不到的数据,在数据库中也没有取到,这时也能够将 key-value 对写为 key-null,缓存无效工夫能够设置短一些,如 30 秒(设置太长会导致失常状况也没法应用)。这样能够避免攻打用户重复用同一个 id 暴力攻打

缓存击穿

缓存击穿指的是大量的 key 在同一时间过期,然而又有大量的申请须要用到这些曾经过期的 key,那么程序在 redis 找不到数据,就会去数据库里查问,数据库解决大量的申请的同时导致压力霎时增大,造成压力过大,甚至导致解体;

解决方案

  1. 设置 key 值永不过期
  2. 将 key 的过期工夫设为随机
  3. 减少互斥锁,当多个 key 过期时,同一时间只有一个查问申请下发到数据库,其余的 key 期待一个个地轮流查,就能够防止数据库压力过大的问题;代码如下:

     static Lock lock = new ReentrantLock();
     
     public String getData(String key) throws InterruptedException {
         try {
             // 从 redis 获取值
             String data =  getRedisData(key);
             // 如果 key 不存在,从数据库查问
             if(null  == data){
                 // 尝试获取锁
                 if(!lock.tryLock()){
                    // 获取锁失败 ,100ms 后在次尝试
                     TimeUnit.MILLISECONDS.sleep(100);
                     data = getData(key);
                 }
                 // 走到这里示意胜利获取锁
    
                 // 从 myqsl 中获取锁
                 data = getMysqlData(key);
    
                 // 将数据更新到 redis
                 setDataToRedis(key,value);
             }
             return data;
         } catch (Exception e){e.printStackTrace();
             throw e;
         } finally {
             // 解锁
             lock.unlock();}
     }

    穿透和击穿的区别

    对于穿透和击穿的区别下面曾经介绍的很分明了,这里在做个总结

  4. 穿透:大量申请了缓存和数据库中都没有的数据,每次都查询数据库,导致数据库压力过大
  5. 击穿:大量 key 在同一时间过期,导致所有申请都达到数据库,导致数据库压力过大

雪崩效应

雪崩效应指的是由穿透和击穿引起的数据库压力过大,最初导致整个数据库宕机,一旦数据库崩了,它所带来的连锁反应是可怕的,数据库不可用的状况下你的服务器也无奈应用;这就是雪崩效应;

退出移动版