天天看點

Redis中緩存雪崩、緩存穿透、緩存降級等概念的簡單說明

Redis中緩存雪崩、緩存穿透、緩存降級等概念的簡單說明(言簡意赅,不啰嗦):
      1、緩存雪崩:緩存集中過期,新緩存還沒能刷入進來,導緻所有請求(查詢)都走資料庫,給資料庫記憶體和CPU巨大壓力,嚴重導緻資料庫當機,進而造成系統崩潰。
          (1)、在并發數不是特别多的情況下,最多的解決方案是加鎖排隊。
            public object GetProductListNew()
            {
                const int cacheTime = 30;
                const string cacheKey = "product_list";
                const string lockKey = cacheKey;
        
                  var cacheValue = CacheHelper.Get(cacheKey);
                  if (cacheValue != null)
                  {
                      return cacheValue;
                  }
                  else
                  {
                      lock (lockKey)
                      {
                          cacheValue = CacheHelper.Get(cacheKey);
                          if (cacheValue != null)
                          {
                                return cacheValue;
                          }
                          else
                          {
                              cacheValue = GetProductListFromDB(); //這裡一般是 sql查詢資料。              
                              CacheHelper.Add(cacheKey, cacheValue, cacheTime);
                          }                    
                      }
                      return cacheValue;
                 }
            } 
          (2)、加鎖排隊隻是保護了資料庫,并沒有提高吞吐量,在高并發下,緩存重建期key是鎖着的,導緻使用者等待逾時。
                另一個解決方法是:給每一個緩存資料增加相應的緩存标記,記錄緩存是否失效,如果緩存失效,從新刷入緩存。
                public object GetProductListNew()
                {
                    const int cacheTime = 30;
                    const string cacheKey = "product_list";
                    //緩存标記。
                    const string cacheSign = cacheKey + "_sign";
        
                    var sign = CacheHelper.Get(cacheSign);
                    //擷取緩存值
                    var cacheValue = CacheHelper.Get(cacheKey);
                    if (sign != null)
                    {
                        return cacheValue; //未過期,直接傳回。
                    }
                    else
                    {
                        CacheHelper.Add(cacheSign, "1", cacheTime);
                        ThreadPool.QueueUserWorkItem((arg) =>
                        {
                            cacheValue = GetProductListFromDB(); //這裡一般是 sql查詢資料。
                            CacheHelper.Add(cacheKey, cacheValue, cacheTime*2); //過期時間設緩存時間的2倍,用于髒讀。                
                        });
            
                        return cacheValue;
                    }
                } 
                
                
        緩存标記:記錄緩存資料是否過期,如果過期會觸發另外的線程在背景去更新實際key的緩存。
        緩存資料:資料的過期時間是緩存标記的過期時間的2倍,當緩存标記key過期後,實際緩存還能把舊資料傳回給使用者,直到另外的線程在背景更新完緩存後,才傳回新緩存的資料。
          
        設定緩存時候,盡量設定為一個随機的過期時間,盡量避免大量的緩存設定相同的過期時間,避免集中過期。
   
  2、緩存穿透
        這其實就是緩存命中率問題:使用者查找的資訊(例:id),在資料庫中不存在,緩存中更沒有。這就造成,每次都去資料庫查一次,然後傳回空。
        解決辦法就是:如果查詢資料庫為空,直接設定一個預設的緩存值到緩存,這樣再通路這個資料的時候,直接傳回預設值,不會再通路資料庫了。對需要查詢的key進行預先的校驗,校驗通過的再放行給後面的正常的緩存處理邏輯。
        
        public object GetProductListNew()
        {
            const int cacheTime = 30;
            const string cacheKey = "product_list";

            var cacheValue = CacheHelper.Get(cacheKey);
            if (cacheValue != null)
                return cacheValue;
            
            cacheValue = CacheHelper.Get(cacheKey);
            if (cacheValue != null)
            {
                return cacheValue;
            }
            else
            {
                cacheValue = GetProductListFromDB(); //資料庫查詢不到,為空。
            
                if (cacheValue == null)
                {
                    cacheValue = string.Empty; //如果發現為空,設定個預設值,也緩存起來。                
                }
                CacheHelper.Add(cacheKey, cacheValue, cacheTime);
            
                return cacheValue;
            }
        }    
  3、緩存預熱
        所謂預熱,就是在使用者使用之前,把需要緩存的資料,先緩存到緩存系統。
        操作方法:
           (1)、寫個刷緩存的程式,上線前,手動刷一下。
           (2)、通路量低谷時定期定時刷緩存(淩晨3點-4點)。
  4、緩存更新
        (1)、通路量低谷時定期定時刷緩存淩晨3點-4點)。        
        (2)、當有使用者請求時,再去判斷是否過期,過期的話,再更新緩存。 
  5、緩存降級
        (1)、緩存降級:核心就是棄車保帥,保證核心服務可用,降級可以丢棄的服務,可以讓程式實施自動降級,也可以人工緊急降級。
  6、分布式緩存系統的問題
        (1)、緩存系統與底層資料庫的一緻性。底層系統是可讀可寫時,很重要。
        (2)、緩存分層時候,不同層緩存的一緻性。例如:全局緩存,二級緩存,全局緩存可以有二級緩存來組成。
        (3)、多個緩存副本的一緻性。緩存系統背後往往是兩套緩存系統(如memcached、redis等)。
  7、緩存淘汰:
        (1)、定時定期去清理過期的緩存。
        (2)、使用者請求時再去更新緩存。
  8、緩存算法(緩存滿了時候,那種緩存先淘汰)
        (1)、FIFO算法,先進先出。先緩存,先被淘汰。
        (2)、LFU算法,最不經常使用算法。 
        (3)、LRU算法,近期最少使用算法。
        
  備注: 根據部落格和《深入了解redis》一書了解和整理。