一、先給緩存雪崩定個性:啥是 Redis 緩存雪崩?

你可以把 Redis 緩存想象成超市的自助收銀台,數據庫就是超市的人工收銀台。正常情況下,用户(請求)都走自助收銀台(緩存),人工收銀台(數據庫)壓力很小;而緩存雪崩,就是 “所有自助收銀台同時壞了”—— 大量緩存數據在同一時間失效,或者 Redis 服務直接掛了,導致所有請求瞬間全衝到數據庫上,數據庫扛不住這麼大壓力,直接崩潰,整個系統就癱瘓了。

舉個最常見的例子:你給一批商品緩存設置了相同的過期時間(比如都是凌晨 1 點過期),到了 1 點,這批緩存全失效,剛好凌晨 1 點又有一波用户訪問,所有請求都去查數據庫,數據庫直接被打垮。

二、為啥會發生緩存雪崩?(兩大核心原因)

  1. 緩存批量失效(最常見)
  • 人為設置了統一的過期時間:比如做活動時,給所有活動商品緩存設了 2 小時過期,2 小時後緩存全失效;
  • 緩存 Key 的過期時間 “扎堆”:比如用時間戳 + 固定時長設置過期,導致大量 Key 在同一時間段過期。
  1. Redis 服務整體掛了
  • Redis 集羣宕機(比如服務器斷電、網絡故障、Redis 進程崩潰);
  • 突發流量打垮 Redis(比如秒殺活動,請求量遠超 Redis 處理能力)。

三、怎麼解決緩存雪崩?(從易到難,新手也能落地)

1. 先解決 “緩存批量失效” 的問題

  • 過期時間加隨機值(最簡單有效)給每個 Key 的過期時間都加一個隨機數,避免 “扎堆失效”。比如原本要設 2 小時過期,就改成 “2 小時 ± 10 分鐘”,讓緩存失效時間分散開。代碼示例(Java):
    java運行
// 原過期時間:7200秒(2小時)
int baseExpire = 7200;
// 隨機加0-600秒(10分鐘)
int randomExpire = new Random().nextInt(600);
// 最終過期時間:7200~7800秒
redisTemplate.opsForValue().set("goods:1001", goodsInfo, baseExpire + randomExpire, TimeUnit.SECONDS);
  • 核心數據永不過期對系統核心、訪問量極高的數據(比如首頁輪播圖、熱門商品),不設置過期時間,由程序手動更新緩存(比如商品價格變了,再更新緩存),避免這些數據失效。

2. 解決 “Redis 掛了” 的問題

  • Redis 集羣化部署(高可用)不要只部署一台 Redis,用主從複製 + 哨兵模式,或者 Redis Cluster 集羣。就算一台 Redis 掛了,其他節點能立刻頂上,不會導致緩存服務整體不可用。
  • 添加緩存降級 / 熔斷機制當 Redis 掛了,不是直接把所有請求丟給數據庫,而是做 “降級處理”:
  • 比如返回兜底數據(“當前系統繁忙,請稍後再試”);
  • 用熔斷器(比如 Sentinel)限制訪問數據庫的請求量,避免數據庫被沖垮。

3. 終極兜底:保護數據庫

  • 數據庫加讀寫分離 / 分庫分表:提升數據庫本身的抗壓力;
  • 加分佈式鎖 / 限流:限制同一時間訪問數據庫的請求數,比如用 Guava 的 RateLimiter 做接口限流;
  • 開啓緩存預熱:在流量高峯前(比如秒殺開始前),提前把熱點數據加載到緩存裏,避免高峯時緩存為空。

四、緩存雪崩 vs 緩存擊穿 vs 緩存穿透(新手別搞混)

很多新手會把這三個概念弄混,簡單區分一下:

問題

核心場景

影響範圍

緩存雪崩

大量緩存同時失效 / Redis 掛了

整個系統(數據庫崩潰)

緩存擊穿

單個熱點 Key 失效(比如秒殺商品)

單個 Key 對應的數據庫請求

緩存穿透

請求不存在的 Key(比如查 ID=-1 的商品)

直接穿透緩存到數據庫

總結

  1. 緩存雪崩的核心:大量緩存同時失效 / Redis 宕機,導致請求全衝數據庫,系統癱瘓;
  2. 預防關鍵:過期時間加隨機值分散失效、Redis 集羣保證高可用、給數據庫加限流 / 降級兜底;
  3. 新手優先落地:先給過期時間加隨機值(成本最低),再部署 Redis 主從集羣(提升可用性)。