1、快取和資料庫不一致
只要我們使用 Redis 快取,就必然會面對快取和資料庫間的一致性保證問題,這裡的“一致性”包含了兩種情況:快取中有資料且與資料庫中的值相同、快取中沒有資料,最新值在資料庫中。
對於讀寫快取來說,要想保證快取和資料庫中的資料一致,就要採用同步直寫策略,在業務應用中使用事務機制,來保證快取和資料庫的更新具有原子性。對資料一致性的要求不高的場景,可以使用非同步寫回策略。
只讀快取在新增資料時是符合資料一致性第二種情況的,但是在刪改資料時,無論是操作快取還是運算元據庫,有一項失敗,就會產生資料不一致的問題。具體情況如圖:
針對這種情況可以引用重試機制來解決,具體來說,可以把要資料暫存到訊息佇列中。無論哪項操作失敗,都可以從訊息佇列中重新讀取這些值,然後再次進行刪除或更新。如果刪改成功,就把資料從訊息佇列中去除,以免重複操作,以此來保證資料一致性。多次重試仍然失敗的話就需要業務層面預警來排查解決了。
除了操作失敗的原因,實際當有大量併發請求時,應用還是有可能讀到不一致的資料。根據刪改快取、資料庫的先後順序分為兩種情況:先操作快取和先運算元據庫。透過引用“延遲雙刪”的操作,來保證先操作快取後運算元據庫的資料一致性問題,程式碼示意如下:
redis.delKey(X)
db.update(X)
Thread.sleep(N)
redis.delKey(X)
具體情況與應對措施總結如圖:
2、雪崩
指大量的應用請求無法在 Redis 快取中進行處理,到達資料庫層面,導致資料庫的壓力激增。原因有二:
其一,快取中有大量資料同時過期。
其二,Redis 快取例項掛了。
原因一可以透過以下兩個方法解決:
(1)微調過期時間:對於同一批資料設定不同的過期時間,如透過隨機數延遲過期等。
(2)降級處理:非核心資料請求直接返回 空 或 錯誤 等預置資訊,核心資料執行未命中快取訪問資料庫。
原因二可以透過以下兩個方法解決:
(1)熔斷:拒絕快取客戶端的請求,保護資料庫,防止整個系統崩潰,直到 Redis 快取例項恢復正常,但是對業務應用的影響範圍大。
(2)限流:允許部分請求到達 Redis 快取,無法命中再訪問資料庫,減輕資料庫壓力,相對於熔斷來說影響範圍稍微縮小。
無論採取何種措施,雪崩都已經發生了,必定會影響到業務系統,所以要做好預防工作,構建 Redis 快取高可靠叢集,儘量避免事故。
3、擊穿
指標對某個熱點資料的請求,無法在快取中處理,大量訪問該資料的請求傳送到了後端資料庫,壓力激增影響到其他請求,如下圖:
為了避免快取擊穿給資料庫帶來的激增壓力,對於訪問特別頻繁的熱點資料,可以不設定過期時間了,全部在快取中進行處理。
4、穿透
指要訪問的資料既不在 Redis 快取中,也不在資料庫中,導致請求壓力還是落到資料庫,快取也就成了“擺設”。如下圖:
通常情況是由於業務資料被誤刪除,或者惡意攻擊訪問,有三種方案解決快取穿透的影響:
(1)快取空值或預設值:針對穿透的資料,在 Redis 中快取一個空值或是和業務層協商確定的預設值,避免把大量請求傳送給資料庫。
(2)布隆過濾器
布隆過濾器由一個初值都為 0 的 bit 陣列和 N 個雜湊函式組成,資料入庫則進行標記,過程如下:
- 使用 N 個雜湊函式,分別計算這個資料的雜湊值,得到 N 個雜湊值。
- 我們把這 N 個雜湊值對 bit 陣列的長度取模,得到每個雜湊值在陣列中的對應位置。
- 我們把對應位置的 bit 位設定為 1,這就完成了在布隆過濾器中標記資料的操作。
當查詢某個資料時,按照雜湊函式的計算結果,檢視 bit 陣列中這 N 個位置上的 bit 值,只要有一個不為 1,這就表明布隆過濾器沒有對該資料做過標記。當快取穿透發生,布隆過濾器的快速檢測特性可以幫資料庫阻擋大部分的壓力。例子如下圖:
(3)前端請求過濾:在請求入口前端進行合法性檢測,把惡意的請求(如請求引數不合理、非法值或請求欄位不存在)直接過濾掉。
小結
雪崩、擊穿、穿透,這三類異常問題從成因來看,前兩個主要是因為資料不在快取中了,而穿透則是因為資料既不在快取中,也不在資料庫中。當雪崩或擊穿發生時,一旦資料庫中的資料被再次寫入到快取後,應用又可以在快取中快速訪問資料了,資料庫的壓力也會相應地降低,而穿透發生時,Redis 快取和資料庫會同時持續承受請求壓力。
對應的熔斷、降級、限流這些方法都是屬於“有損”方案,在保證資料庫和整體系統穩定的同時,會對業務應用帶來負面影響。降級時,有部分資料的請求就只能得到錯誤返回資訊,無法正常處理。熔斷時,整個快取系統暫停,影響的業務範圍更大。流機時,整個業務系統的吞吐率會降低,併發處理能力減弱,影響到使用者體驗。
所以,應當儘量使用預防式方案,總結如下:
- 雪崩,合理地設定資料過期時間,以及搭建高可靠快取叢集。
- 擊穿,在快取訪問非常頻繁的熱點資料時,不要設定過期時間。
- 穿透,提前在入口前端實現惡意請求檢測,或者規範資料庫的資料刪除操作,避免誤刪除。