一提到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、業務層對請求進行檢測
快取穿透發生的原因主要就是惡意請求訪問不存在的資料,所以業務層接受到請求後,一定要進行合法性檢測,把惡意請求給過濾掉,這樣就可以避免快取穿透的問題了。
今天我們就聊到這裡,如果感興趣,記得關注一波公眾號【程式設計師學長】,有你意想不到的收穫哦。