REDIS快取穿透 擊穿 雪崩 原因及解決方案

2021-10-19 18:32:06 字數 2760 閱讀 4373

在我們日常的開發中,無不都是使用資料庫來進行資料的儲存,由於一般的系統任務中通常不會存在高併發的情況,所以這樣看起來並沒有什麼問題,可是一旦涉及大資料量的需求,比如一些商品搶購的情景,或者是主頁訪問量瞬間較大的時候,單一使用資料庫來儲存資料的系統會因為面向磁碟,磁碟讀/寫速度比較慢的問題而存在嚴重的效能弊端,一瞬間成千上萬的請求到來,需要系統在極短的時間內完成成千上萬次的讀/寫操作,這個時候往往不是資料庫能夠承受的,極其容易造成資料庫系統癱瘓,最終導致服務宕機的嚴重生產問題。

為了克服上述的問題,專案通常會引入nosql技術,這是一種基於記憶體的資料庫,並且提供一定的持久化功能。

redis技術就是nosql技術中的一種,但是引入redis又有可能出現快取穿透,快取擊穿,快取雪崩等問題。本文就對這三種問題進行較深入剖析。

乙個一定不存在快取及查詢不到的資料,由於快取是不命中時被動寫的,並且出於容錯考慮,如果從儲存層查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義。

有很多種方法可以有效地解決快取穿透問題,最常見的則是採用布隆過濾器,將所有可能存在的資料雜湊到乙個足夠大的bitmap中,乙個一定不存在的資料會被 這個bitmap攔截掉,從而避免了對底層儲存系統的查詢壓力。另外也有乙個更為簡單粗暴的方法(我們採用的就是這種),如果乙個查詢返回的資料為空(不管是資料不存在,還是系統故障),我們仍然把這個空結果進行快取,但它的過期時間會很短,最長不超過五分鐘。

粗暴方式偽**:

//偽**

public object getproductlistnew()

cachevalue = cachehelper.

get(cachekey);if

(cachevalue != null)

else

cachehelper.

add(cachekey, cachevalue, cachetime)

;return cachevalue;

}}

key可能會在某些時間點被超高併發地訪問,是一種非常「熱點」的資料。這個時候,需要考慮乙個問題:快取被「擊穿」的問題。

使用互斥鎖(mutex key)

業界比較常用的做法,是使用mutex。簡單地來說,就是在快取失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用快取工具的某些帶成功操作返回值的操作(比如redis的setnx或者memcache的add)去set乙個mutex key,當操作返回成功時,再進行load db的操作並回設快取;否則,就重試整個get快取的方法。

setnx,是「set if not exists」的縮寫,也就是只有不存在的時候才設定,可以利用它來實現鎖的效果。

public string get

(key)

else

}else

}

memcache**:

if

(memcache.

get(key)

== null)

else

}

與快取擊穿的區別在於這裡針對很多key快取,前者則是某乙個key。

快取正常從redis中獲取,示意圖如下:

快取失效瞬間示意圖如下:

快取失效時的雪崩效應對底層系統的衝擊非常可怕!大多數系統設計者考慮用加鎖或者佇列的方式保證來保證不會有大量的執行緒對資料庫一次性進行讀寫,從而避免失效時大量的併發請求落到底層儲存系統上。還有乙個簡單方案就時講快取失效時間分散開,比如我們可以在原有的失效時間基礎上增加乙個隨機值,比如1-5分鐘隨機,這樣每乙個快取的過期時間的重複率就會降低,就很難引發集體失效的事件。

加鎖排隊,偽**如下:

//偽**

public object getproductlistnew()

else

else

}return cachevalue;

}}

加鎖排隊只是為了減輕資料庫的壓力,並沒有提高系統吞吐量。假設在高併發下,快取重建期間key是鎖著的,這是過來1000個請求999個都在阻塞的。同樣會導致使用者等待超時,這是個治標不治本的方法!

注意:加鎖排隊的解決方式分布式環境的併發問題,有可能還要解決分布式鎖的問題;執行緒還會被阻塞,使用者體驗很差!因此,在真正的高併發場景下很少使用!

隨機值偽**:

//偽**

public object getproductlistnew()

else);

return cachevalue;

}}

解釋說明:關於快取崩潰的解決方法,這裡提出了三種方案:使用鎖或佇列、設定過期標誌更新快取、為key設定不同的快取失效時間,還有一種被稱為「二級快取」的解決方法。

針對業務系統,永遠都是具體情況具體分析,沒有最好,只有最合適。

於快取其它問題,快取滿了和資料丟失等問題,大夥可自行學習。最後也提一下三個詞lru、rdb、aof,通常我們採用lru策略處理溢位,redis的rdb和aof持久化策略來保證一定情況下的資料安全。

Redis快取穿透,穿透擊穿,快取雪崩

乙個一定不存在快取及查詢不到的資料,由於快取是不命中時被動寫的,並且出於容錯考慮,如果從儲存層查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義。有很多種方法可以有效地解決快取穿透問題,最常見的則是採用布隆過濾器,將所有可能存在的資料雜湊到乙個足夠大的bit...

redis 快取穿透 擊穿 雪崩

介面層增加校驗,如使用者鑑權校驗,id做基礎校驗,id 0的直接攔截 從快取取不到的資料,在資料庫中也沒有取到,這時也可以將key value對寫為key null,快取有效時間可以設定短點,如30秒 設定太長會導致正常情況也沒法使用 這樣可以防止攻擊使用者反覆用同乙個id暴力攻擊 public o...

redis快取穿透,擊穿,雪崩

快取穿透 描述 快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷發起請求,多來自於黑客攻擊。由於快取是不命中時被動寫的,並且出於容錯考慮,如果從儲存層查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義。在流量大時,可能db就掛掉了,要是有人利用不存在的k...