Redis緩存三大坑:穿透、擊穿、雪崩
緩存的作用
緩存就像你家冰箱,常用的東西(數據)放裏面,拿的時候快;冰箱沒有的,再去菜市場(數據庫)買。但這三種問題,本質都是"冰箱出了狀況,導致菜市場被擠爆"。
1. 緩存穿透
大白話解釋:查一個"根本不存在的東西",緩存裏沒有,數據庫裏也沒有。結果就是,每次查這個東西,都要去數據庫查一遍,相當於冰箱裏沒有,你還天天去菜市場問有沒有"龍肉",菜市場天天白忙活。
例子:黑客故意用不存在的用户ID(比如 user:-1)瘋狂請求,緩存裏沒這個ID的數據,每次都查數據庫,數據庫壓力驟增,甚至被打垮。
特點:請求的是"不存在的數據",緩存和數據庫都沒有,導致請求直接穿透到數據庫。
2. 緩存擊穿
大白話解釋:某個"熱門數據"的緩存突然過期了(比如緩存時間到了),而此時剛好有大量請求來查這個數據。結果就是,這些請求一下子都衝到數據庫,把數據庫查崩了。相當於你家冰箱裏的"網紅奶茶"剛喝完(緩存過期),突然來了100個人要買,你只能趕緊去菜市場進貨,菜市場瞬間被擠爆。
例子:某商品做活動,緩存了它的庫存,結果緩存突然過期,同時有10萬用户點擊購買,都去數據庫查庫存,數據庫扛不住。
特點:針對"一個熱門數據",緩存過期的瞬間,大量請求穿透到數據庫。
3. 緩存雪崩
大白話解釋:很多緩存"在同一時間過期",或者緩存服務器直接掛了。結果就是,大量請求一下子全衝到數據庫,數據庫直接被壓垮。相當於你家冰箱突然停電,裏面所有東西都壞了(緩存失效),這時候全村人都去菜市場買菜,菜市場直接被擠塌了。
例子:電商大促零點,很多商品的緩存都是提前1小時設置的,到零點同時過期,millions of請求瞬間涌向數據庫,數據庫直接宕機。
特點:"大量緩存同時失效"或"緩存服務器掛了",導致數據庫瞬間承受巨大壓力。
三者的區別總結
- 穿透:查"不存在的數據",每次都打數據庫
- 擊穿:查"熱門數據",緩存剛好過期,瞬間大量請求打數據庫
- 雪崩:"大量緩存同時失效"或緩存掛了,所有請求打數據庫
都是緩存沒起到作用,導致數據庫壓力過大,但觸發原因和範圍不同。
解決方案
1. 緩存穿透(查不到的東西總來查)
- 給"不存在的數據"也搞個緩存:比如查一個不存在的用户ID,數據庫返回空,就在緩存裏存個"空值"(比如
null),並設個短過期時間(比如5分鐘)。這樣下次再查,直接從緩存拿空值,不用去煩數據庫。 - 加個"守門的":用布隆過濾器先擋一輪,把所有可能存在的合法數據提前"記下來"。請求來的時候,先過過濾器,不是合法數據直接打回去,根本不讓它到緩存和數據庫那一步。
2. 緩存擊穿(熱門數據緩存過期,一堆人搶着查)
- 讓熱門數據"永不過期":要麼不設過期時間,要麼後台定時更新緩存(比如每隔10分鐘更一次),不讓它自己過期。
- 加把"鎖":當緩存過期時,只讓一個請求去數據庫查,其他請求等着。比如第一個請求發現緩存沒了,就先拿個鎖,查完數據庫更新緩存後再釋放鎖,其他人就直接從緩存拿數據了,避免一窩蜂衝去數據庫。
3. 緩存雪崩(大量緩存同時過期/緩存崩了)
- 別讓緩存"一起過期":給緩存的過期時間加個"隨機數",比如本來想設1小時,就改成"1小時±10分鐘",讓過期時間錯開,避免扎堆失效。
- 多搞幾個緩存服務器:搞個集羣,就算其中一台崩了,其他的還能頂上去(類似多個人看門,一個不在還有別人)。
- 給數據庫也減減壓:暫時用"降級"策略,比如返回舊數據、提示"稍等再試",先保證數據庫別崩。
- 提前備好"冷備"緩存:比如把緩存數據存一份到其他地方(像本地文件),萬一緩存集羣崩了,先從冷備裏拿數據頂一陣子。
解決方案總結
- 穿透靠"攔空值、設門檻"
- 擊穿靠"鎖單路、永不過期"
-
雪崩靠"錯時間、多備份"