Redis緩存穿透、緩存擊穿、緩存雪崩解決方案和分析
緩存穿透
使用者或黑客惡意大量通路緩存資料庫中沒有的資料,導緻大量請求湧至關系型資料庫,導緻資料庫當機,這就是緩存穿透。
解決方案:
(1)利用互斥鎖,緩存失效的時候,先去獲得鎖,得到鎖了,再去請求資料庫。沒得到
鎖,則休眠一段時間重試
(2)采用異步更新政策,無論 key 是否取到值,都直接傳回。value 值中維護一個緩存
失效時間,緩存如果過期,異步起一個線程去讀資料庫,更新緩存。需要做緩存預熱(項目
啟動前,先加載緩存)操作。
(3)提供一個能迅速判斷請求是否有效的攔截機制,比如,利用布隆過濾器,内部維護
一系列合法有效的 key。迅速判斷出,請求所攜帶的 Key 是否合法有效。如果不合法,則直
接傳回。
(4) 如果從資料庫查詢的對象為空,也放入緩存,隻是設定的緩存過期時間較短,比如
設定為 60 秒。
緩存擊穿
緩存擊穿多發生在高并發的環境下,在電商搶購商品可能會發生,比如A商品作為搶購商品放在緩存資料庫中,當搶購截止時,緩存資料庫的A商品資訊失效,而此時仍有大量使用者在請求A商品的資訊,這時便導緻大量請求打到資料庫上,可能造成資料庫壓力徒增,壓垮資料庫
解決方案:
其實,大多數情況下這種爆款很難對資料庫伺服器造成壓垮性的壓力。達到這個級别的
公司沒有幾家的。是以,對主打商品都是早早的做好了準備,讓緩存永不過期。即便某些商
品自己發酵成了爆款,也是直接設為永不過期就好了。
(1) 從 redis 上看,确實沒有設定過期時間,這就保證了,不會出現熱點 key 過期問
題,也就是“實體”不過期。
(2) 從功能上看,如果不過期,那不就成靜态的了嗎?是以我們把過期時間存在 key
對應的 value 裡,如果發現要過期了,通過一個背景的異步線程進行緩存的建構,也就是
“邏輯”過期。
緩存雪崩
緩存雪崩,是指緩存同一時間大面積的失效,這個時候又來了一波請求,結果請求都怼
到資料庫上,進而導緻資料庫連接配接異常。
産生雪崩的原因之一,比如商城馬上就要到雙十一零點,很快就會迎來一波搶購,這波
商品時間比較集中的放入了緩存,假設緩存一個小時。那麼到了淩晨一點鐘的時候,這批商
品的緩存就都過期了。而對這批商品的通路查詢,都落到了資料庫上,對于資料庫而言,就
會産生周期性的壓力波峰。
其實集中過期,倒不是非常緻命,比較緻命的緩存雪崩,是緩存伺服器某個節點當機或
斷網。因為自然形成的緩存雪崩,一定是在某個時間段集中建立緩存,那麼那個時候資料庫
也是可以頂住壓力的,無非就是對資料庫産生周期性的壓力而已。而緩存服務節點的當機,
對資料庫伺服器造成的壓力是不可預知的,很有可能瞬間就把資料庫壓垮。
解決方案:
做電商項目的時候,一般是采取不同分類商品,緩存不同周期。在同一分類中的商品,
加上一個随機因子。這樣能盡可能分散緩存過期時間,而且,熱門類目的商品緩存時間長一
些,冷門類目的商品緩存時間短一些,也能節省緩存服務的資源。
(1)給緩存的失效時間,加上一個随機值,避免集體失效。
(2)使用互斥鎖,但是該方案吞吐量明顯下降了。
(3)雙緩存。我們有兩個緩存,緩存 A 和緩存 B。緩存 A 的失效時間為 20 分鐘,緩存 B
不設失效時間。自己做緩存預熱操作。然後細分以下幾個小點
a. 從緩存 A 讀資料庫,有則直接傳回
b. A 沒有資料,直接從 B 讀資料,直接傳回,并且異步啟動一個更新線程。
c. 更新線程同時更新緩存 A 和緩存 B。