害...原來阿裏面試常問的Redis面試題是它啊!

公眾號程序員學長 2021-08-15 16:56:47 阅读数:87

本文一共[544]字,预计阅读时长:1分钟~
redis

   一提到Redis緩存,我們不得不了解的三個問題就是:緩存雪崩、緩存擊穿和緩存穿透。這三個問題一旦發生,會導致大量的請求直接請求到數據庫層。如果並發壓力大,就會導致數據庫崩潰。那p0級的故障是沒跑了。

   今天我們就來詳細的了解這個三個問題誘因以及如何解决。沒有點關注,記得先點個關注吧。 廢話不多說,我們直接開搞!!!

一、緩存雪崩

   什麼是緩存雪崩?緩存雪崩就是大量請求無法在redis緩存中進行處理,而是直接發送到了數據庫層,使得數據庫壓力陡增。就好像redis一下子突然失效了一樣。一般造成緩存雪崩主要有兩個原因,我們來一一分析一下。

1.緩存中大量數據同時過期

   緩存中大量數據同時過期,就會導致大量請求無法在redis緩存層面進行處理。具體來說,就是給redis中大量數據設置了相同的過期時間,一旦它們同時失效,應用就會把請求直接發送給數據庫,直接從數據庫中讀取數據。如果應用的並發量很大,那數據庫的壓力就會很大。如下圖所示:   

   針對大量數據同時失效帶來的緩存雪崩問題,我們一般采取以下兩種解决方案。   (1)我們在開發過程中要避免給大量數據設置相同的過期時間。我們可以在給數據設置過期時間時給時間加一個很小的隨機數,這樣不同數據的過期時間就會有所差別,但差別也不會太大,保證數據在一定範圍內過期,從而滿足業務層要求同時過期的需要。   (2)服務降級。所謂的服務降級,是指發生緩存雪崩後,針對不同的數據采取不同的策略。

  • 當業務訪問非核心數據時(例如商品屬性信息),我們直接返回預定義的信息。
  • 當業務訪問的是如庫存數據等核心數據時,仍然允許查詢緩存,如果緩存缺失,也可以從數據庫中繼續讀取。

   這樣一來,只有部分過期的數據會訪問數據庫,所以數據庫壓力就沒那麼大。

2.Redis實例發生故障

   當Redis實例發生故障,那就相當於緩存已經廢掉了,所以大量請求會直接請求數據庫,造成數據庫壓力變大,甚至宕機。針對這種情况發生的緩存雪崩,我們有以下兩種處理方式。 (1)在業務系統側實現服務熔斷或請求限流機制    所謂的服務熔斷,就是指在發生緩存雪崩時,為了防止大流量直接打到數據庫,我們會暫停對緩存系統的訪問。當上層應用訪問緩存時,緩存接口不會去訪問Redis實例,而是直接返回。等redis恢複後,再允許應用程序請求緩存系統。這樣就會避免因為redis緩存宕機,導致數據庫壓力陡增的情况。
   服務熔斷雖然可以保證數據庫不被崩潰,但是暫停了整個服務的訪問,對業務的影響範圍大,為了减小對上層服務的影響,我們一般采用請求限流。請求限流是指業務系統去控制每秒進入系統的請求數,避免過多的請求被發送到數據庫。比如正常運行時,業務系統每秒進入的請求是1萬個,其中有80%在緩存中就可以處理了,有20%會去數據庫中處理。一旦發生緩存雪崩,100%的流量就會請求數據庫,為了不造成數據庫崩潰,我們就可以啟動請求限流機制。業務系統只允許30%的流量進入,而70%的流量被拒絕服務。這也是目前主流大廠常用的方法,比如在某個明星爆出大瓜後,我們刷微博經常刷不出來,多刷幾次就能進入,那就是因為做了服務降級。只允許一部分流量進入。

   (2)使用高可靠集群     

     我們可以通過主從節點來部署高可靠的Redis集群。當主節點掛掉後,從節點還可以切換成主節點。

二、緩存擊穿

    緩存擊穿是指針對某個熱點數據,無法在緩存中進行處理,然後訪問該數據的大量請求,一下子都發到後端數據庫中,導致數據庫壓力激增。對於緩存擊穿的情况,經常發生在熱點數據過期失效時
    為了避免這種情况發生,最常采取的措施就是對於訪問特別頻繁的熱點數據,我們就不設置過期時間了。這樣一來,對熱點數據的訪問,都可以在緩存中進行。

三、緩存穿透

   緩存穿透是指要訪問的數據既不在緩存中,也不在數據庫中,會導致請求緩存時,發生緩存缺失,然後請求數據庫,發現數據庫中也沒有需要的數據。這樣一來,緩存就成了“擺設”,如果有大量的這種請求,就會給數據庫帶來很大的壓力。
   這個問題一般都是黑客進行惡意攻擊造成的。為了避免這種問題發生,我們有三種解决方式。

1、緩存空值或者缺省值

    一旦發生緩存穿透,我們就可以在redis中設置一個空值或者給定的某個缺省值。這樣,業務應用的後續這種請求,都可以命中緩存。這樣就避免了把大量請求發送給數據庫了。

2、使用布隆過濾器來快速判斷數據是否存在

   這裏我們先來解釋一下什麼是布隆過濾器。
   布隆過濾器由一個初值都為0的bit數組和N個哈希函數組成,可以用來快速判斷某個數據是否存在。當我們想標記某個數據存在時,布隆過濾器會通過三個操作來完成標記:

  • 首先,使用N個哈希函數,分別計算數據的哈希值,得到N個哈希值。
  • 然後把這N個哈希值對bit數組的長度取模,得到每個哈希值在數組中的比特置。
  • 最後,我們把對應比特置的bit比特設置為1,這樣就完成了布隆過濾器中標記數據的操作。

   如果數據不存在,也就是我們沒有用布隆過濾器標記過,bit數組對應的bit比特為0。    當我們需要判斷某個數據是否存在時,我們就執行上面的計算過程,我們先求出這個數據對應的hash值,然後取模,然後去bit數組查這N個比特置上的bit值。只要這N個bit值有一個不為1,就錶明這個數據沒有被標記過。    基於布隆過濾器的快速檢測特性,我們可以把數據寫入數據庫時,使用布隆過濾器做個標記,當緩存失效後,上層應用查詢數據庫時,可以通過查詢布隆過濾器快速判斷數據是否存在。如果不存在,就不用在去數據庫中去查了。這樣一來,即使發生緩存穿透,也不會對數據庫造成壓力。

3、業務層對請求進行檢測

   緩存穿透發生的原因主要就是惡意請求訪問不存在的數據,所以業務層接受到請求後,一定要進行合法性檢測,把惡意請求給過濾掉,這樣就可以避免緩存穿透的問題了。
今天我們就聊到這裏,下一次我們來聊聊Redis分布式鎖的問題,如果感興趣,記得關注一波哦。

 

版权声明:本文为[公眾號程序員學長]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815165635233l.html