1. 程式人生 > >Redis快取篇(四)快取異常

Redis快取篇(四)快取異常

這一節,我們來學習一下快取異常。快取異常有四種類型,分別是快取和資料庫的資料不一致、快取雪崩、快取擊穿和快取穿透。

下面通過了解這四種快取異常的原理和應對方法。

快取和資料庫的資料不一致

快取和資料庫的資料一致性包含兩種情況:

  • 快取中有資料,快取的資料值需要和資料庫中的值相同;
  • 快取中沒有資料,資料庫中的值必須是最新值。

資料不一致是如何發生的?

在第1講中關於快取的型別那節,介紹了快取有兩種不同型別,分別是隻讀快取和讀寫快取。不同型別的快取資料不一致的發生情況不一樣,應對方法也不一樣。

讀寫快取:有兩種寫回策略,同步直寫和非同步寫回。如果要保證資料一致,就要採用同步直寫策略。但需要保證快取和資料庫的更新具有原子性,即要麼都成功,要麼都失敗。

只讀快取:分新增資料和刪改資料兩種情況說明。

新增資料

資料直接寫到資料庫中,不對快取做任何操作,符合一致性的第2種情況。

刪改資料

發生刪改操作時,既要更新資料庫,也要在快取裡刪除資料。因為快取和資料庫是不同的系統,這裡分兩種情況:

  • 先刪除快取,再更新資料庫:資料庫更新失敗,導致請求再次訪問快取時,發現快取失敗,再讀資料庫時,從資料庫中讀取舊值。
  • 先更新資料庫,再刪除快取:快取刪除失敗,導致請求再次訪問快取時,發現快取命中,並從快取中讀取到舊值。

如何解決資料不一致?

使用重試機制,指把刪除的快取值或者是要更新的資料庫值暫存到訊息佇列中(例如使用Kafka訊息佇列)。

當應用沒有能夠成功地刪除快取值或者是更新資料庫值時,從訊息佇列中重新讀取這些值,然後再次進行刪除或更新。

如果成功刪除,就從訊息佇列中刪除,以免重複操作。否則就要進行重試,如果重試超過一定次數,就要向業務層傳送報錯資訊。

具體情況如下圖所示:

總結一下,對於只讀快取來說,建議優先使用先更新資料庫,再刪除快取。

快取雪崩

快取雪崩,指大量的應用請求無法在Redis快取中進行處理,然後應用將大量請求傳送到資料庫層,導致資料庫層的壓力激增。

導致快取雪崩的兩個原因:

1. 快取中有大量資料同時過期,導致大量請求無法得到處理。

解決方案有兩個,一是避免給大量的資料設定相同的過期時間,增加一個較小的隨機數(例如,隨機增加1~3分鐘)。

另一個是服務降級,服務降級指發生快取雪崩時,針對不同的資料採取不同的處理方式:

  • 非核心資料,暫時停止從快取中查詢,直接返回預定義資訊、空值或者錯誤資訊;
  • 核心資料,允許查詢快取,如果快取缺失,繼續通過資料庫讀取。

2. Redis快取例項發生故障宕機了,無法處理請求。

有兩個建議,一是在業務系統中實現服務熔斷或請求限流機制。

服務熔斷是指在發生快取雪崩時,為了防止引發連鎖的資料庫雪崩,暫停業務應用對快取系統的介面訪問。

具體點,就是業務應用呼叫快取介面時,快取客戶端並不把請求發給Redis快取例項,而是直接返回,等Redis快取例項重新恢復服務後,再允許傳送。

服務熔斷會暫停了整個快取系統的訪問,對業務應用的影響範圍大。而請求限流相比服務熔斷造成的影響沒那麼大。

請求限流是指業務系統的請求入口前端控制每秒進入系統的請求數,避免過多的請求被髮送到資料庫。

二是事前預防,通過主從節點構建Redis快取高可靠叢集。

快取擊穿

快取擊穿,指標對某個訪問非常頻繁的熱點資料的請求,無法在快取中進行處理,大量請求傳送到後端資料庫,導致資料庫壓力激增,影響資料庫處理其他請求。

解決方案是,對於訪問特別頻繁的熱點資料,不設定過期時間。

快取穿透

快取穿透,指要訪問的資料既不在Redis快取中,也不在資料庫中,導致請求在訪問快取時,發生快取缺失,再去訪問資料庫時,也發現沒有資料。

如果有大量請求訪問資料,就會同時給快取和資料庫帶來巨大壓力。

發生快取穿透有兩種情況:

  • 業務層誤操作:快取中的資料和資料庫中的資料被誤刪除;
  • 惡意攻擊:專門訪問資料庫中沒有的資料。

為了避免快取穿透,有三種應對方案。

第一種方案是,快取空值或預設值

一旦發生快取穿透,就針對查詢的資料,在Redis中快取一個空值或是和業務層協商確定的預設值。

第二種方案是,使用布隆過濾器快速判斷資料是否存在,避免從資料庫中查詢資料是否存在,減輕資料庫壓力

布隆過濾器由一個初值都為0的bit陣列和N個雜湊函式組成,可以用來快速判斷某個資料是否存在。

通過三個操作完成標記:

  • 使用N個雜湊函式,分別計算這個資料的雜湊值,得到N個雜湊值
  • 把這N個雜湊值對bit陣列的長度取模,得到每個雜湊值的位置
  • 把對應的位置的bit位設定為1

這樣一來,即使發生快取穿透,大量請求只會查詢Redis和布隆過濾器。

第三種方案是,在請求入口的前端進行請求檢測

例如對請求進行合法性檢測,把惡意的請求(例如請求引數不合理、請求引數是非法值、請求欄位不存在)直接過濾掉

總結

另外還有三個建議:

  • 針對快取雪崩,合理地設定資料過期時間,以及搭建高可靠快取叢集。
  • 針對快取擊穿,在快取訪問非常頻繁的熱點資料時,不要設定過期時間。
  • 針對快取穿透,提前在入口前端實現惡意請求檢測,或者規範資料庫的資料刪除操作,避免誤刪除。

參考資料

  • 25 | 快取異常(上):如何解決快取和資料庫的資料不一致問題?
  • 26 | 快取異常(下):如何解決快取雪崩、擊穿、穿透難題?