怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩

怎么解讀redis緩存穿透、緩存擊穿和緩存雪崩,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、小程序開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了棗莊免費建站歡迎大家使用!

一、緩存穿透

1、概念

緩存穿透是指查詢一個數(shù)據(jù)庫一定不存在的數(shù)據(jù)。正常的使用緩存流程大致是,數(shù)據(jù)查詢先進行緩存查詢,如果key不存在或者key已經(jīng)過期,再對數(shù)據(jù)庫進行查詢,并把查詢到的對象,放進緩存。如果數(shù)據(jù)庫查詢對象為空,則不放進緩存。

這里需要注意緩存擊穿的區(qū)別,緩存擊穿,緩存擊穿是指緩存中沒有但數(shù)據(jù)庫中有的數(shù)據(jù),并且某一個key非常熱點,在不停的扛著大并發(fā),大并發(fā)集中對這一個點進行訪問,當(dāng)這個key在失效的瞬間(一般是緩存時間到期),持續(xù)的大并發(fā)就穿破緩存,直接請求數(shù)據(jù)庫,就像在一個屏障上鑿開了一個洞。

為了避免緩存穿透其實有很多種解決方案。下面介紹幾種

2、解決方案

(1)布隆過濾器

布隆過濾器是一個bit向量或者bit,如果我們要映射一個值到布隆過濾器中,我們使用多個不同的哈希函數(shù)生成多個哈希值,并將每個生成的哈希值指向的bit位設(shè)置為1,如下baidu一詞設(shè)置了三個位置為1。

原理:對一個key進行k個hash算法獲取k個值,在比特數(shù)組中將這k個值散列后設(shè)定為1,然后查的時候如果特定的這幾個位置都為1,那么布隆過濾器判斷該key存在。

怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩

“tencent”一詞,對應(yīng)的情況
怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩
可以看到,不同的詞對應(yīng)的bit位置可能相同,當(dāng)詞很多的情況時,可能大部分bit位置都是1,這時查詢taobao可能對應(yīng)的位置都為1,只能說明taobao一詞可能存在,不是一定存在的,這時1就被覆蓋了,這就是布隆過濾器的誤判。如果它說不存在那肯定不存在,如果它說存在,那數(shù)據(jù)有可能實際不存在。

Redis的bitmap只支持2^32大小,對應(yīng)到內(nèi)存也就是512MB,誤判率萬分之一,可以放下2億左右的數(shù)據(jù),性能高,空間占用率及小,省去了大量無效的數(shù)據(jù)庫連接。

因此我們可以通過布隆過濾器,將Redis緩存穿透控制在一個可容范圍內(nèi)。

怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩

使用布隆過濾器:
導(dǎo)入依賴

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>19.0</version>
</dependency>

代碼:

public class Test {

   private static int size = 1000000;//預(yù)計要插入多少數(shù)據(jù)

   private static double fpp = 0.01;//期望的誤判率

   private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);

   public static void main(String[] args) {
       //插入數(shù)據(jù)
       for (int i = 0; i < 1000000; i++) {
           bloomFilter.put(i);
       }
       int count = 0;
       for (int i = 1000000; i < 2000000; i++) {
           if (bloomFilter.mightContain(i)) {
               count++;
               System.out.println(i + "誤判了");
           }
       }
       System.out.println("總共的誤判數(shù):" + count);
   }
}

應(yīng)用:

@Cacheable(value="key1")
public String get(String key) {
   String value = redis.get(key);  
   // redis中不存在該緩存
   if (value  == null) {
   //布隆過濾器也沒有,直接返回
       if(!bloomfilter.mightContain(key)){
           return null;
       }else{
           //布隆過濾器中能查到,不代表一定有,查出來放入redis,同樣也可以避免緩存穿透
           value = db.get(key);
           redis.set(key, value);
       }    
   }
   return value;
}

(2)、緩存空對象
當(dāng)存儲層不命中后,即使返回的空對象也將其緩存起來,同時會設(shè)置一個過期時間,之后再訪問這個數(shù)據(jù)將會從緩存中獲取,保護了后端數(shù)據(jù)源。
怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩
但是這種方法會存在兩個問題:

?● 如果空值能夠被緩存起來,這就意味著緩存需要更多的空間存儲更多的鍵,因為這當(dāng)中可能會有很多的空值的鍵;

?● 即使對空值設(shè)置了過期時間,還是會存在緩存層和存儲層的數(shù)據(jù)會有一段時間窗口的不一致,這對于需要保持一致性的業(yè)務(wù)會有影響。

二、緩存雪崩

(1)、概念
緩存雪崩是指緩存中大批量數(shù)據(jù)到過期時間,而查詢數(shù)據(jù)量巨大,引起數(shù)據(jù)庫壓力過大甚至down機。和緩存擊穿不同的是,緩存擊穿指并發(fā)查同一條數(shù)據(jù),緩存雪崩是不同數(shù)據(jù)都過期了,很多數(shù)據(jù)都查不到從而查數(shù)據(jù)庫。
怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩
產(chǎn)生雪崩的原因之一,假如馬上就要到雙十一零點,很快就會迎來一波搶購,這波商品時間比較集中的放入了緩存,假設(shè)緩存一個小時。那么到了凌晨一點鐘的時候,這批商品的緩存就都過期了。而對這批商品的訪問查詢,都落到了數(shù)據(jù)庫上,對于數(shù)據(jù)庫而言,就會產(chǎn)生周期性的壓力波峰。

博主在做電商項目的時候,一般有三種方法:
(1)采取不同分類商品,緩存不同周期。在同一分類中的商品,加上一個隨機因子。這樣能盡可能分散緩存過期時間,而且,熱門類目的商品緩存時間長一些,冷門類目的商品緩存時間短一些,也能節(jié)省緩存服務(wù)的資源。
(2)如果緩存數(shù)據(jù)庫是分布式部署,將 熱點數(shù)據(jù)均勻分布在不同的緩存數(shù)據(jù)庫中。
(3)設(shè)置熱點數(shù)據(jù)永遠不過期。
怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩
(4) 使用加鎖限流的方式
怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩
怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩
怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩

三、緩存擊穿

(1)概念
緩存擊穿,是指緩存中沒有但數(shù)據(jù)庫中有的數(shù)據(jù),并且某一個key非常熱點,在不停的扛著大并發(fā),大并發(fā)集中對這一個點進行訪問,當(dāng)這個key在失效的瞬間(一般是緩存時間到期),持續(xù)的大并發(fā)就穿破緩存,直接請求數(shù)據(jù)庫,就像在一個屏障上鑿開了一個洞。

(2)解決方案

?● 設(shè)置熱點數(shù)據(jù)永遠不過期。

?● 使用互斥鎖(mutex key)
?業(yè)界比較常用的做法,是使用mutex。簡單地來說,就是在緩存失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當(dāng)操作返回成功時,再進行l(wèi)oad db的操作并回設(shè)緩存;否則,就重試整個get緩存的方法。

SETNX,是「SET if Not eXists」的縮寫,也就是只有不存在的時候才設(shè)置,可以利用它來實現(xiàn)鎖的效果。

public String get(key) {
     String value = redis.get(key);
     if (value == null) { //代表緩存值過期
         //設(shè)置3min的超時,防止del操作失敗的時候,下次緩存過期一直不能load db
      if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表設(shè)置成功
              value = db.get(key);
              redis.set(key, value, expire_secs);
              redis.del(key_mutex);
         } else {  //這個時候代表同時候的其他線程已經(jīng)load db并回設(shè)到緩存了,這時候重試獲取緩存值即可
              sleep(50);
              get(key);  //重試
             }
     } else {
         return value;      
  }
}

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。

文章題目:怎么解讀Redis緩存穿透、緩存擊穿和緩存雪崩
文章轉(zhuǎn)載:http://bm7419.com/article12/jjscgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、網(wǎng)站內(nèi)鏈、網(wǎng)站建設(shè)外貿(mào)網(wǎng)站建設(shè)、微信小程序移動網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站制作