緩存雪崩
大量緩存數據在同一時間過期或者Redis故障宕機時,若此時有大量請求,都會直接訪問到數據庫,導致數據庫壓力倍增甚至宕機。
大量數據同時過期解決方案:
1、均勻設置過期時間:
設置過期時間的時候可以追加一個隨機數,避免數據同一時間過期。
2、互斥鎖:
業務線程處理用戶請求時,如果發現訪問的數據不在Redis里,則加入互斥鎖,保證同一時間只有一個業務線程訪問數據庫并構建緩存。未獲取到互斥鎖的請求要么等待鎖釋放后獲取緩存,要么返回指定值。注意:互斥鎖應該設置過期時間,避免獲取鎖的線程意外阻塞導致鎖無法釋放,造成無響應的情況。
3、后臺更新緩存:
將更新緩存的工作交給后臺線程進行更新
- 第一種方式:后臺頻繁檢測緩存是否有效,檢測到緩存失效后(可能是內存資源不足被淘汰的)就馬上訪問數據庫并更新到緩存。
- 缺點:
- 檢測時間間隔不能太長,一般是毫秒級,有延遲問題
- 頻繁檢測存在性能開銷
- 第二種方式:業務線程發現緩存失效后,通過消息隊列發送一條信息通知后臺線程更新緩存。后臺線程收到消息后進行判斷數據是否已被緩存,沒有則訪問數據庫構建緩存。
- 優點:
- 消息隊列中可根據相同請求冪等性實現互斥鎖的效果,無需加鎖,所有請求都等待緩存構建或返回指定值即可。
- 消息隊列具有削峰作用,高并發時也能保證數據庫正常運行
業務剛上線時我們就可以提前把數據緩存起來,而不是等待用戶來觸發緩存構建,這就是所謂的緩存預熱。
Redis宕機解決方案:
1、服務熔斷或請求限流機制
- 服務熔斷機制,暫停業務對緩存服務的訪問,直接返回錯誤,而不是繼續訪問數據庫,直到Redis恢復正常。
- 請求限流機制,只接收少部分請求發送到數據庫進行處理,再多的請求就在入口直接拒絕服務,直到待Redis恢復正常
2、構建Redis高可靠集群
當前Redis宕機后依然可通過其他從節點獲取緩存。
緩存擊穿
緩存中的某個熱點數據過期,此時大量請求直接訪問到數據庫。(緩存雪崩是多種多個數據請求,緩存擊穿是訪問熱點數據的大量請求)
解決方案:
- 互斥鎖:保證同一時間只有應該業務線程共享緩存。
- 后臺異步更新緩存:不再給熱點請求設置過期時間,或熱點數據快過期時通知后臺線程更新緩存并重新設置緩存時間。
緩存穿透
發生緩沖雪崩或擊穿時,數據庫中是有對應數據的,而緩沖穿透則是數據庫中也無法獲取到對應數據的情況。如果數據庫無法獲取數據就無法構建緩存,造成緩存失效。通常發生于業務誤操作刪除了數據和惡意訪問不存在的數據。
解決方案:
1、限制非法請求:
在訪問緩存或數據庫前判斷請求的參數是否合理,過濾不合理請求
2、緩存空值或默認值
若業務發現有緩存穿透的現象,可以針對查詢數據在緩存中設置空值或者默認值
3、布隆過濾器
使用布隆過濾器快速判斷數據是否存在,避免通過查詢數據庫來判斷
布隆過濾器的實現:
由初始值都為0的位圖數組(Bitmap,連續二進制位序列)和N個哈希函數兩部分組成。我們在寫入數據庫數據的同時對布隆過濾器做標記,這樣后續的查詢就可根據布隆過濾器快速判斷數據是否存在。
過濾操作:
- 第一步,使用N個哈希函數分別對數據進行哈希計算,得到N個哈希值
- 第二步,將第一步得到的N個哈希值對位圖數組的長度進行取模,得到每個哈希值的對應位置
- 第三步,將每個哈希值在位圖數組中的對應位置設為1
假設有一個長度為8的位圖數組,3個哈希函數的布隆過濾器:
查詢時,分別計算出數據N個哈希值對應的位置并判斷是否全為1。只要有一個為0就說明數據不存在。
布隆過濾器也是存在哈希沖突的,哈希沖突時可能將不存在的查詢數據誤判為已存在(與數據庫中存在的數據發生了哈希沖突)。但數據庫中不存在的數據在布隆過濾器中就一定不存在
通過增加哈希函數的數量,可盡量減少因為哈希沖突發生誤判的情況。