缓存雪崩及其解决方案

问题缓存雪崩:

          缓存服务器挂掉,或者热点缓存失效,导致大量的请求访问DB数据库,导致数据库连接不够用或数据库处理不过来,从而导致系统不可用。

    类比缓存击穿:

               缓存雪崩产生的原因--缓存曾经存在,只是失效或者缓存服务器挂掉

               而缓存击穿,是指访问缓存中必然不存在的数据,故意绕过缓存,直接访问数据库导致的

               简单描述一下缓存击穿的解决方案:当访问数据库中不存在的数据时,可以给这个key设置一个固定值,并设置过期时间,这样的话,大量的访问该key的请求,都被缓存挡住了;当key存在数据时,缓存也已经失效,在去访问,就可以访问数据库更新这个key的值了

    解决方案:

   1.限流: 加锁,控制进入数据库请求数量

               private Lock lock  = new ReentrantLock();

               public String queryInfo(String key){

                       //step1:先从缓存中获取,获取不到,接着向下走

                      try{

                               //step2:加锁

                               lock.lock();

                              // step3:获取到锁后,再次从缓存中取数据

                             // 这样做的目的是,验证是否已经有其他请求已经查询到数据,并放入缓存中去了

                             // step4:到数据库中查询

                            // step5 : 查询的结果放入缓存 

                      }finally{

                         // step6: 解锁

                         lock.unlock();

                      }

             }

           

         这种方案的缺点:

                        1) 线程阻塞,导致用户体验不好

                        2) 加锁的粒度太大,对所有进入到这个方法的请求加锁,即所有的查询都被一把锁锁住

   2.服务降级 :把锁的粒度变小,使用 ConcurrentHashMap加锁

private Map<String,String> lockMap = new ConcurrentHashMap<>();

public String queryInfo(String key){

     //step1:先从缓存中获取,获取不到,接着向下走

    boolean lock = false;

    try{
        //step2:类似加锁
        lock = lockMap.putIfAbsent(key,"lock") == null;
        //拿到锁的线程,负责更新缓存,其他请求读取备份缓存或者执行降级策略
        if(lock){
            //step3:继续从缓存中获取
            // 这样做的目的是,验证是否已经有其他请求已经查询到数据,并放入缓存中去了

           // step4:到数据库中查询

           // step5 : 查询的结果放入缓存 ,包括备份缓存
        }else{
            //服务降级策略
            // 策略1:从备份缓存中获取
            // 策略2:返回一个固定值
        }
    }finally {
        // 最后解锁:
        lockMap.remove(key);
    }

}

   

    优点:线程不阻塞,用户体验好

    缺点:数据不一致,缓存维护复杂

3.写定时任务去刷新更新热点缓存

猜你喜欢

转载自blog.csdn.net/lihongtai/article/details/82555508
今日推荐