快取穿透 快取雪崩和快取擊穿

2021-10-03 14:48:48 字數 1413 閱讀 2872

快取系統是我們平時開發經常使用到的,也是在高併發場景下減少或防止流量對db等底層系統衝擊的最有效手段之一。下面就簡單談談快取系統經常提及的三個問題以及解決方案。

首先回憶下通常情況我們設定的快取機制,如下圖所示:

快取載入機制

這套機制,由於出於容錯考慮,從儲存層查不到資料則不寫入快取,這就導致每次請求不存在的資料時都要到儲存層去查詢。如果有黑客可以利用不存在的key,頻繁請求我們的伺服器,這些請求就會穿透快取,直接打到db上,對db造成巨大壓力甚至掛掉。這就是快取穿透。

解決方案

有很多種方法可以有效地解決快取穿透問題,最常見的則是採用布隆過濾器(bloom filter)。

布隆過濾器是將所有可能存在的資料雜湊到乙個足夠大的bitmap中,乙個一定不存在的資料會被 這個bitmap攔截掉,從而避免了對底層儲存系統的查詢壓力。

另外乙個更為簡單粗暴的方法,如果乙個查詢結果空(不管是數 據不存在,還是查詢異常),我們仍然把這個空結果進行快取,但它的過期時間會很短,幾分鐘即可。

快取雪崩是指在如果我們幾乎在同一時間設定的快取(比如快取預熱),並且設定了相同的過期時間,這就會導致快取會在某一時刻同時失效,這個時間所有請求會全部**到db,db瞬時壓力過重雪崩。

解決方案

大多數系統設計者考慮用加鎖或者佇列的方式保證快取的單線 程(程序)寫,從而避免失效時大量的併發請求落到底層儲存系統上。另乙個簡單的方案就是我們可以在原有的失效時間基礎上增加乙個隨機值,讓快取的失效時間錯開,就可以有效的避免快取雪崩。

解決方案

1.使用互斥鎖(mutex lock):

簡單地來說,就是在快取失效的時候,不是直接請求db,而是先加分布式鎖(比如redis的setnx),如果加鎖成功,再進行load db的操作並回設快取;如果加鎖失敗,說明已經有別的程序在加鎖重設快取,我們只需要等待重試或者直接返回客戶端失敗讓使用者手動重試。

這是比較簡單,也是很常用的一種解決方式。值得注意的是,我們加鎖的時候一定要設定過期時間(如redis的expire),否則會有死鎖的風險。

2. 提前更新快取:

上面一種方案,因為使用者是有感知的,如果不想影響使用者體驗,可以進一步優化為對快取加標,並記錄它的過期時間,當我們讀取快取的時候,先判斷它是否快到過期時間,如果是則在返回快取資料的同時,後台非同步請求db重設快取,更新它的過期時間。而如果我們獲取快取是快取已經過期,則還需要我們按照上乙個方案處理。

3. "永不失效":

在上面情況下,我們進一步思考,如果我們設定快取的過期時間非常長(比如3天),同時我們對快取加標記錄設定快取的時間,每次我們讀取快取的時候,拿到設定快取的時間跟現在的時間做比對,如果相差時間超過10分鐘,我們在後台非同步更新快取。這樣對於熱點資料而言,就相當於快取「永不失效」了。

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

q 快取穿透,是指查詢乙個資料庫一定不存在的資料。正常的使用快取流程大致是,資料查詢先進行快取查詢,如果key不存在或者key已經過期,再對資料庫進行查詢,並把查詢到的物件,放進快取。如果資料庫查詢物件為空,則不放進快取。a 1.布隆過濾器,將所有可能存在的資料雜湊到乙個足夠大的bitmap中,乙個...

快取擊穿 快取穿透和快取雪崩

快取擊穿 定義 快取中的key一般設有過期時間,如果某個key過期了,恰在這個時候,有大量的併發請求訪問這個key,則這些請求都會到達db,導致db瞬間壓力過大,壓垮db。解決方案 1.設定互斥鎖,mutex。當快取失效時不時立即去訪問資料庫,而是使用快取工具的操作成功帶返回值的操作,比如redis...

快取穿透 快取雪崩和快取擊穿

快取穿透的概念很簡單,使用者想要查詢乙個資料,發現redis記憶體資料庫沒有,也就是快取沒有命中,於是向持久層資料庫查詢。發現也沒有,於是本次查詢失敗。當使用者很多的時候,快取都沒有命中 秒殺 於是都去請求了持久層資料庫。這會給持久層資料庫造成很大的壓力,這時候就相當於出現了快取穿透。布隆過濾器 布...