1、緩存雪崩
在給 key 設置過期時間的策略上沒有限制,給一大堆的 key 設置了相同的過期時間,當達到過期時間的時,在某一刻有一堆的 key 都被清除了,這個時候,新來的請求全部去數據庫請求,數據庫瞬時訪問壓力過重而扛不住的情況。假如這個時候掛的是一個用戶服務的數據庫,這個時候所有依賴這個庫的接口都會報錯,就算重啓,用戶的請求依舊會把數據庫搞掛,反覆來個幾次,用戶也不玩了。
解決辦法
最簡單的解決方法就是把緩存失效的時間分散開來,例如可以在本來的失效時間上增加一個隨機值,這樣就不會有大量的 key 在同一時刻失效了。
2、緩存擊穿
緩存擊穿有點像緩存雪崩,但是又有些不一樣,這種情況都是發生在設置了過期時間的 key,如果某個會過期的 key 在某個時間點可能被超高併發地訪問,就有可能發生這個問題。假如恰巧在 key 過期的時候,又有大量對這個 Key 的併發請求過來,這個時候發現緩存過期,便會去數據庫讀取數據,同樣因爲請求量過大而搞掛數據庫。
解決方法
1、可以設置熱點數據永遠不過期;例如 Redis 角度,不設置過期時間。
2、也可以加上互斥鎖,在緩存失效的時候(判斷拿出來的值爲空),不立即去數據庫讀取數據,先使用帶成功操作返回值的接口(比如 set 接口)獲取一把鎖,獲取鎖成功後,再去數據庫讀取數據,然後把讀到的數據設置到緩存裏,如果獲取鎖失敗,就重新讀 Redis 的緩存。
3、緩存穿透
當去 Redis 查詢一個一定不存在的 key 時,因爲緩存不會命中,就會去數據庫讀取,一般出於容錯的考慮,在數據庫查不到數據時,不會寫入 Redis 中,而這種查詢不存在的 key 時,每次請求都會跑去數據庫查詢,Redis 這層緩存就失去了意義。在流量大的時候,或者有人惡意使用不存在的 key 去查詢的時候,就會把數據庫搞掛。
解決方法
我記得華爲學習手冊裏面有這樣一種定義 —— 可信域、不可信域。對外提供的接口,因爲調用方不是自己的程序,不能確定調用者會爲這個接口傳遞什麼參數,所以傳遞的參數是不可信。大體是這樣描述,細節記不清楚了,基於這一條,加強對參數的校驗,從而屏蔽這種不可信可能造成的潛在危機。
上述的方法只是降低了緩存穿透的概率,並不能完全解決,所以還需要有一定的補充。當從 Redis 中取不到數據,且數據庫中也沒有數據,這時把這個 key 的 value 寫爲 null 或者什麼(根據具體情況而定),同時把緩存超時時間設置的短一點,避免由於設置過長導致的正常情況也沒法使用。
一般情況下,正常用戶,不會有意頻繁去嘗試無效 key 的請求,所以,可以讓運維人員設置每個 IP 每秒可以訪問次數的限制。