天天看點

緩存雪崩及其解決方案

問題緩存雪崩:

          緩存伺服器挂掉,或者熱點緩存失效,導緻大量的請求通路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.寫定時任務去重新整理更新熱點緩存

繼續閱讀