有一天凌晨 2 點,監控突然像過年放鞭炮一樣,全紅。QPS 飆升、數據庫 CPU 100%、連接池打滿、報警電話響到我懷疑人生。同事迷迷糊糊地問我一句:
“是不是緩存雪崩了?”
那一刻,我才真正意識到:
Redis 不只是快,它也可能是一場“雪災”。
從一個真實又殘酷的故事説起
想象一個場景。你在北方某城市生活,這座城市冬天靠集中供暖。平時大家都很舒服,屋裏 25 度,外面零下十幾度也不慌。
某天,供暖公司為了方便管理,統一設置:凌晨 3 點檢修。結果會發生什麼?
- 3:00 整座城市同時斷暖
- 千家萬户瞬間降温
- 大家同時打開電暖氣
- 小區電閘直接拉閘
- 整個系統徹底癱瘓
你是不是已經開始瑟瑟發抖了?
Redis 緩存雪崩,本質上就是這一幕
緩存 = 供暖系統數據庫 = 電網 / 發電站請求 = 家庭用電
當大量緩存在同一時間失效,所有請求瞬間打到數據庫,數據庫扛不住,就直接“崩”。
面試官口中的標準定義
面試時你可以先給一個非常乾淨、標準的定義:
緩存雪崩:指在某一時間點,大量緩存數據同時失效,導致原本由緩存承擔的請求全部落到數據庫,數據庫在短時間內承受巨大壓力,最終可能宕機。
如果你能補一句:
“這是高併發系統中非常典型的一類級聯故障。”
面試官一般會點頭。
緩存雪崩是怎麼“雪”起來的?
1、最常見的作死操作:統一過期時間
很多系統,剛開始寫緩存代碼時是這樣的:
看起來很合理,對吧?但如果你是批量加載緩存呢?
然後悲劇來了
- 00:00 批量加載緩存
- 00:30 所有緩存同時過期
- 00:30:01 所有請求直衝數據庫
這不是雪崩,這是定時炸彈。
2、緩存節點整體不可用(進階版雪崩)
除了過期時間問題,還有一種更狠的情況:
- Redis 宕機
- 網絡抖動
- 主從切換失敗
這時:不是“緩存失效”,而是“緩存消失”,所有請求,毫無緩衝,直接懟數據庫。
雪崩發生時,系統會長什麼樣?
我們用一張表來直觀感受一下:
你會發現一個事實:緩存雪崩從來不是“緩存的問題”,而是“數據庫被拖下水”的問題。
解決方案一:緩存過期時間加隨機值(最基礎)
不要讓整座城市同一秒斷暖,而是:
- 這棟樓 2:55
- 那棟樓 3:03
- 再遠一點 3:17
分批降温,電網就能扛住。
1、正確的緩存姿勢
這樣做的效果:
- 緩存不會同一時間失效
- 數據庫流量被“攤平”
- 成本低、實現簡單
2、適用場景
解決方案二:加鎖排隊(併發不高時最常用)
這招,在面試和實際項目裏都非常常見。
先説核心思想:緩存失效時,只允許一個線程去查數據庫,其它線程等着。
就像:
- 一個窗口賣票
- 排隊買
- 不能一擁而上把窗口拆了
1、偽代碼邏輯
2、執行過程拆解
3、優點與缺點
解決方案三:緩存標記位(進階但非常優雅)
這是我非常喜歡的一種方案,因為它——像一個成熟的系統工程師思路。
1、先來個生活類比
你去便利店買盒飯,發現:
- 盒飯在
- 但貼着一個標籤:“待補貨”
你會怎麼做?
- 你不會衝進後廚自己做
- 你會等店員補貨
2、技術層面的思路
緩存中不僅存數據,還存“狀態”,狀態包括:
- 是否過期
- 是否正在重建
3、數據結構設計
3、核心代碼示意
異步重建緩存
4、這種方案的特點
三種方案對比表格
面試時怎麼一口氣説漂亮?
如果面試官問你:
“Redis 緩存雪崩怎麼解決?”
你可以這樣回答:
緩存雪崩主要是由於大量緩存同一時間失效導致的。
常見解決方案包括:
第一,給緩存過期時間增加隨機值,避免集中失效;
第二,在併發量不高的情況下,可以通過加鎖控制只有一個線程重建緩存;
第三,更成熟的做法是引入緩存標記位或邏輯過期,緩存過期後先返回舊值,再異步更新,避免請求直接打到數據庫。
這一段,説完,基本穩了。
最後聊一句掏心窩子的
緩存不是銀彈。
- 它能救你
- 也能埋你
真正成熟的系統,從來不是“用了 Redis 就萬事大吉”,而是:你是否為“緩存失效的那一刻”做好了準備。
END
我是小米,一個喜歡分享技術的31歲程序員。如果你喜歡我的文章,歡迎關注我的微信公眾號“軟件求生”,獲取更多技術乾貨!
我們,下篇見。