如何解決Redis快取雪崩、擊穿與穿透

2022-11-03 18:00:49
本篇文章給大家帶來了關於的相關知識,其中主要介紹了關於怎麼解決redis快取雪崩、擊穿與穿透的相關問題,快取雪崩是指大量的請求無法命中Redis中的快取資料,也就是在Redis找不到資料了;下面一起來看一下,希望對大家有幫助。

千萬級資料並行如何處理?進入學習

推薦學習:

一、快取雪崩

1. 什麼是快取雪崩?

快取雪崩是指大量的請求無法命中Redis中的快取資料,也就是在Redis找不到資料了,那業務系統只能到資料庫中查詢,進而導致所有的請求都傳送到了資料庫。如下圖所示:

資料庫並不像Redis能處理大量請求,由快取雪崩導致的請求激增必須會導致資料庫所在宕機,這樣勢必會影響業務系統,所以如果發生快取雪崩,對於業務系統肯定是致命的。

2. 為什麼發會生快取雪崩?

什麼情況下出現快取雪崩呢?總結起來有以下兩個方面的原因:

  • 大量Redis快取資料同時過期,導致所有的傳送到Redis請求都無法命中資料,只能到資料庫中進行查詢。

  • Redis伺服器宕機,所有請求都無法經Redis來處理,只能轉向資料庫查詢資料。

3. 如何避免快取雪崩?

針對導致快取雪崩的原因,有不同的解決方法:

  • 針對大量快取隨機過期時間,解決方法就是在原始過期時間的基礎上,再加一個隨機過期時間,比如1到5分鐘之間的隨機過期時間,這樣可以避免大量的快取資料在同一時間過期。

  • 而針對Redis解決宕機的導致的快取雪崩,可以提前搭建好Redis的主從伺服器進行資料同步,並設定哨兵機制,這樣在Redis伺服器因為宕機而無法提供服務時,可以由哨兵將Redis從伺服器設定為主伺服器,繼續提供服務。

二、快取擊穿

1. 什麼是快取擊穿

快取擊穿與快取雪崩的情況相似,雪崩是因為大量的資料過期,而快取擊穿則是指熱點資料過期,所有針對熱點資料的請求都需要到資料庫中進行處理,如下圖所示:

2. 怎麼避免快取擊穿?

解決快取擊穿的三種方式:

  • 不設定過期時間

如果我們能提前知道某個資料是熱點資料,那麼就可以不設定這些資料的過期,從而避免快取擊穿問題,比如一些秒殺活動的商品,在秒殺時會大量使用者存取,這時候我們就可以將這些用於秒殺的商品資料提前寫入快取並且不設定過期時間。

  • 互斥鎖

提前知道某些資料會有大量存取,我們當然可以設定不過期,但更多時候,我們並不能提前預知,這種情況要怎麼處理呢?

我們來分析一下快取擊穿的情況:

正常情況下,當某個Redis快取資料過期時,如果有對該資料的請求,則重新到資料庫中查詢並再寫入快取,讓後續的請求可以命中該快取而無須再去資料庫中查詢。

而熱點資料過期時,由於大量請求,當某個請求無法命中快取時,會去查詢資料庫並重新把資料寫入Redis,也就是在寫入Redis之前,其他請求進來,也會去查詢資料庫。

好了,我們知道熱點資料過期後,很多請求會去查詢資料庫,那麼我們可以給去查詢資料庫的業務邏輯加個互斥鎖,只有獲得鎖的請求才能去查詢資料庫並把資料寫回Redis,而其他沒有獲得鎖的請求只能等待資料就緒。

上述步驟的如下圖所示:

  • 設定邏輯過期時間

使用互斥鎖雖然可以非常簡單地解決快取擊穿問題,但沒有獲得鎖的請求雖然排隊等待,這樣影響了系統的效能,還有另一種解決快取擊穿的方法就是在業務資料冗餘一個過期時間,比如下面的資料中我們增加了expire_at欄位用於表示資料過期時間。

{"name":"test","expire_at":"1599999999"}複製程式碼
登入後複製

這種方式的實現過程如下圖所示:

快取中的熱點資料中冗餘一個邏輯過期時間,但資料在Redis不設定過期時間

當一個請求拿到Redis中的資料時,判斷邏輯過期時間是否到期,如果沒有到期,直接返回,如果到期則開啟另一個執行緒獲得鎖後去查詢資料庫並將查詢的最新資料寫回Redis,而當前請求返回已經查詢的資料。

三、快取穿透

1. 什麼是快取穿透

快取穿透是指要查詢的資料既不在快取當中,也不在資料庫中,因為不在快取中,所以請求一定會到達資料庫,Redis快取形同虛設,如下圖所示:

2. 為什麼會發生快取穿透

什麼條件下會發生快取穿透呢?主要有以下三種情況:

  • 使用者惡意攻擊請求

  • 誤操作把Redis和資料庫裡的資料刪除了

  • 使用者還未產生內容時,比如使用者的文章列表,使用者還未寫文章,所以快取和資料庫都沒有資料

3. 如何避免快取穿透?

a. 快取空值或預設值

當在Redis快取中查詢不到資料時,再從資料庫查詢,如果同樣沒有資料,就直接快取一個空間或預設值,這樣可以避免下次再去查詢資料庫;不過為了防止之後已經資料庫已經相應資料庫,再返回空值問題,應該為快取設定過期時間,或者在產生資料時直接清除對應的快取空值。

b. 布隆過濾器

雖然快取空值可以解決快取穿透問題,但仍然需要查詢一次資料庫才能確定是否有資料,如果有使用者惡意攻擊,高並行地使用系統不存在的資料id進行查詢,所有的查詢都要經過資料庫,這樣仍然會給資料庫帶來很大的壓力。

所以,有沒有不用查詢資料庫就能確定資料是否存在的辦法呢?有的,用布隆過濾器

布隆過濾器主要是兩個部分:bit陣列+N個雜湊函數,其原理為:

  • 使用N個雜湊函數對所要標記的資料進行雜湊值計算。

  • 將計算到的雜湊值對bit陣列的長度取模,這樣可以得到每個雜湊值在bit陣列的位置。

  • 把bit陣列中對應的位置標記為1。

下面是布隆過濾器原理示意圖:

當要進行資料寫入時,執行述述步驟,計算對應bit陣列位置並標識為1,那麼在執行查詢時,就能查詢該資料是否存在了。

另外,由於雜湊碰撞問題導致的誤差,所以不存在的資料經過布隆過濾器後,會被判定為存在,再去查資料庫,不過雜湊碰到的概率很小,用布隆過濾器已經能幫我們攔截大部分的穿透請求了。

Redis本身就支援布隆過濾器,所以我們可以直接使用Redis布隆過濾器,而不用自己去實現,非常方便。

四、小結

快取的雪崩、擊穿、穿透是在業務應用快取時經常會碰到的快取異常問題,其原因與解決方法如以下表示所示:

問題原因解決方法
快取雪崩大量資料過期或Redis伺服器宕機1. 隨機過期時間 2. 主從+哨兵的叢集
快取擊穿熱點資料過期1. 不設定過期時間 2. 加互斥鎖 3. 冗餘邏輯過期時間
快取穿透請求資料庫和Redis都沒有的資料1. 快取空值或預設值 2. 布隆過濾器

推薦學習:

以上就是如何解決Redis快取雪崩、擊穿與穿透的詳細內容,更多請關注TW511.COM其它相關文章!