天天看點

Redis緩存穿透和緩存雪崩

Redis緩存穿透和緩存雪崩

緩存穿透

概念

一般的緩存系統,都是按照key值去緩存查詢,如果不存在對應的value,就應該去DB中查找 。

這個時候,如果請求的并發量很大,就會對後端的DB系統造成很大的壓力。這就叫做緩存穿透。

關鍵詞:緩存value為空;并發量很大去通路DB。

原因

  1. 業務自身代碼或資料出現問題;
  2. 一些惡意攻擊、爬蟲造成大量空的命中,此時會對資料庫造成很大壓力。

解決辦法

  1. 設定布隆過濾器,将所有可能存在的資料哈希到一個足夠大的bitmap中,一個一定不存在的資料會被這個bitmap攔截掉,從避免了對底層存儲系統的查詢壓力。
    布隆過濾器:
    判斷一個元素是否在一個數組裡面,如下圖,利用二進制去做的一個存儲,占用記憶體比較小,0 代表不存在,1 代表存在,添加查詢效率很快,當儲存了一個數值會經過一個算法将對應的值儲存到布隆過濾器的集合上的某個位置,某個位置上可能會存在多個key,當傳進來一個不存在的key值,和集合進行比對,如果比對不上便會傳回一個null
    
    布隆過濾器在redis叢集的上一步,主要是判斷資料是否存在于布隆過濾器中,這樣減少對redis伺服器的壓力。布隆過濾器其原理就是把大資料量加載到記憶體中,判斷資料是否存在。大資料量加載到記憶體中,這樣容易導緻OOM。一般是在應用啟動的時候,進行初始化把資料加載到布隆過濾器中。布隆過濾器所需要占記憶體公式為:設bit數組大小為m,樣本數量為n,失誤率為p。由題可知 n = 500萬,p = 3%(Google布隆過濾器預設為3%,我們也可以修改。
    
    缺點:
    1、1%的誤判率,當有一個key不存在布隆數組中,但是由于這個誤判率,在某個情況下回判斷這個key存在,當這個數組越長誤判率越低,數組越短誤判率越高
    2、當我們要删除某個key值的時候,是會删除我們的資料庫和redis中的内容,但是布隆數組中無法删除,因為數組的某個位置上會存在對個key如果我們要删除的話就是将1變成0,但是會将其中所有的key值都删除
    3.代碼複雜度也會增加,因為我們要額外去維護一個集合,當我們使用redis叢集,布隆過濾器要和redis結合在一起使用。
               
  2. 如果一個查詢傳回的資料為空,不管是資料不存在還是系統故障,我們仍然把這個結果進行緩存,但是它的過期時間會很短最長不超過5分鐘。
    if (list != null && list.size() > 0) {
         redisOperator.set("subCat:" + rootCatId, JsonUtils.objectToJson(list));
    } else {
         redisOperator.set("subCat:" + rootCatId, JsonUtils.objectToJson(list), 5*60);
    }
               

緩存雪崩

因為緩存層承載了大量的請求,有效的保護了存儲 層,但是如果緩存由于某些原因,整體不能夠提供服務,于是所有的請求,就會到達存儲層,存儲層的調用量就會暴增,造成存儲層也會挂掉的情況。緩存雪崩的英文解釋是奔逃的野牛,指的是緩存層當掉之後,并發流量會像奔騰的野牛一樣,大量後端存儲。

當緩存伺服器重新開機或者大量緩存集中在某一個時間段失效,這樣在失效的時候,大量資料會去直接通路DB,此時給DB很大的壓力。

(1)設定redis叢集和DB叢集的高可用,如果redis出現當機情況,可以立即由别的機器頂替上來。這樣可以防止一部分的風險。

(2)使用互斥鎖,在緩存失效後,通過加鎖或者隊列來控制讀和寫資料庫的線程數量。比如:對某個key隻允許一個線程查詢資料和寫緩存,其他線程等待。單機的話,可以使用synchronized或者lock來解決,如果是分布式環境,可以是用redis的setnx指令來解決。

繼續閱讀