Redis之緩存擊穿、穿透、雪崩問題及處理
一、緩存擊穿
(一)概念
某個(gè)熱點(diǎn) Key 過期的瞬間,大量并發(fā)請(qǐng)求同時(shí)打到數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫壓力瞬間飆升,甚至被打崩。
大量并發(fā)請(qǐng)求 ---> 訪問同一個(gè)熱點(diǎn) key
↓
這個(gè) key 正好過期
↓
所有請(qǐng)求同時(shí)繞過 Redis 訪問數(shù)據(jù)庫
↓
DB 瞬間壓力過大(被打爆)(二)緩存擊穿的后果
1. 數(shù)據(jù)庫壓力瞬間飆升
- 熱點(diǎn) Key 過期后,大量并發(fā)請(qǐng)求直接落到數(shù)據(jù)庫
- 數(shù)據(jù)庫瞬間承受超高并發(fā)請(qǐng)求,CPU、IO 占用飆升
2. 系統(tǒng)性能下降
- 數(shù)據(jù)庫響應(yīng)變慢 → 接口響應(yīng)延遲增加
3. 請(qǐng)求可能超時(shí)或失敗
- 高并發(fā)下,整體系統(tǒng)吞吐量下降
4. 可能觸發(fā)雪崩效應(yīng)
- 一個(gè)熱點(diǎn) Key 擊穿導(dǎo)致數(shù)據(jù)庫壓力過大
- 可能影響其他業(yè)務(wù)請(qǐng)求
- 形成連鎖反應(yīng),多個(gè) Key 失效 → 系統(tǒng)整體性能下降
5. 運(yùn)維風(fēng)險(xiǎn)增加
- 數(shù)據(jù)庫連接耗盡、事務(wù)阻塞
- CPU/內(nèi)存占用過高 → 可能導(dǎo)致服務(wù)宕機(jī)
- 需要緊急干預(yù),影響業(yè)務(wù)連續(xù)性
(三)觸發(fā)條件
1. 熱點(diǎn) Key(高訪問頻率)
概念:熱點(diǎn) Key 是指在短時(shí)間內(nèi)被大量請(qǐng)求訪問的數(shù)據(jù)。
特征:訪問量遠(yuǎn)高于其他普通 Key,可能占據(jù)系統(tǒng)絕大部分流量。
具體示例:
- 電商網(wǎng)站的某個(gè)秒殺商品庫存信息
- 熱門文章或新聞詳情頁
- 排行榜數(shù)據(jù),如“本周最熱商品 Top 10”
為什么關(guān)鍵:只有熱點(diǎn)數(shù)據(jù)過期,才會(huì)有大量請(qǐng)求瞬間打到數(shù)據(jù)庫,引發(fā)壓力。
2. Key 過期或被淘汰
概念:緩存中存放的 Key 可能由于以下原因失效:
(1)TTL 到期:設(shè)置了過期時(shí)間,到時(shí)間就失效
(2)手動(dòng)刪除:開發(fā)或運(yùn)維手動(dòng)清理緩存
(3)內(nèi)存淘汰:Redis 達(dá)到內(nèi)存上限,根據(jù) LRU/LFU 策略淘汰 Key
具體示例:
- 設(shè)置 SET product_123 100 EX 60,60 秒后過期
- 服務(wù)器更新產(chǎn)品信息,刪除緩存強(qiáng)制刷新
- Redis 內(nèi)存滿了,大對(duì)象或低頻 Key 被淘汰
為什么關(guān)鍵:Key 過期或消失后,下一次請(qǐng)求會(huì)直接落到數(shù)據(jù)庫,這才是擊穿的直接觸發(fā)點(diǎn)。
3. 高并發(fā)訪問
概念:短時(shí)間內(nèi)大量請(qǐng)求同時(shí)訪問同一個(gè) Key。
特征:瞬時(shí)并發(fā)量遠(yuǎn)高于數(shù)據(jù)庫處理能力。
具體示例:
- 秒殺活動(dòng)開始時(shí),幾千甚至上萬用戶同時(shí)訪問同一商品庫存
- 熱點(diǎn)文章推送后,瞬間大量用戶點(diǎn)擊訪問
為什么關(guān)鍵:如果并發(fā)量很小,即使 Key 過期,數(shù)據(jù)庫也能承受壓力;只有高并發(fā)訪問,才會(huì)引發(fā)真正的緩存擊穿。
4. 少了任意一個(gè)條件,就不會(huì)發(fā)生緩存擊穿
解釋:
- 熱點(diǎn) Key 不存在 → 就算并發(fā)很高,也不會(huì)擊穿數(shù)據(jù)庫(普通 Key 的請(qǐng)求量本來就?。?/li>
- Key 沒有過期或被淘汰 → 緩存命中,所有請(qǐng)求都打到 Redis,不會(huì)落到數(shù)據(jù)庫
- 高并發(fā)訪問 不存在 → 即使 Key 過期,也只有少量請(qǐng)求訪問數(shù)據(jù)庫,數(shù)據(jù)庫能輕松承受
- 所以 三個(gè)條件必須同時(shí)滿足,緩存擊穿才會(huì)發(fā)生。
(四)典型場(chǎng)景
1. 熱門商品詳情
場(chǎng)景描述:
- 電商平臺(tái)的秒殺商品或促銷商品在短時(shí)間內(nèi)被大量用戶訪問
- 每個(gè)用戶都要查詢庫存、價(jià)格、折扣等信息
為什么容易擊穿:
- 熱點(diǎn) Key:這個(gè)商品的緩存是熱點(diǎn),因?yàn)槊霘⒒顒?dòng)期間訪問量極高
- Key 過期或緩存未命中:TTL 到期,或者緩存被手動(dòng)刷新
- 高并發(fā)請(qǐng)求:幾千甚至上萬用戶同時(shí)訪問數(shù)據(jù)庫查詢庫存
技術(shù)后果:
- 數(shù)據(jù)庫瞬時(shí)壓力飆升
- 查詢延遲增加 → 可能出現(xiàn)秒殺失敗或頁面崩潰
2. 排行榜或統(tǒng)計(jì)數(shù)據(jù)
場(chǎng)景描述:
- 熱門文章閱讀量、音樂/視頻播放排行榜、實(shí)時(shí)交易額統(tǒng)計(jì)
- 大量用戶同時(shí)查詢“Top N”數(shù)據(jù)
為什么容易擊穿:
- 熱點(diǎn) Key:排行榜數(shù)據(jù)被頻繁訪問
- Key 過期:排行榜緩存每隔一段時(shí)間刷新一次,TTL 到期或邏輯過期
- 高并發(fā)訪問:緩存過期瞬間,所有請(qǐng)求直接打數(shù)據(jù)庫計(jì)算排行
技術(shù)后果:
- 數(shù)據(jù)庫需要進(jìn)行復(fù)雜聚合計(jì)算,CPU/IO 占用高
- 多個(gè) Key 可能同時(shí)被訪問 → 加劇系統(tǒng)壓力
3. 系統(tǒng)配置或元數(shù)據(jù)
場(chǎng)景描述:
- 經(jīng)常查詢的基礎(chǔ)信息,例如用戶角色權(quán)限、地區(qū)列表、字典表數(shù)據(jù)
- 訪問頻率高,但數(shù)據(jù)量相對(duì)固定
為什么容易擊穿:
- 熱點(diǎn) Key:這些 Key 被多次訪問
- Key 過期或被刷新:配置更新或 TTL 到期
- 高并發(fā)訪問:短時(shí)間內(nèi)多個(gè)服務(wù)/用戶請(qǐng)求這些基礎(chǔ)數(shù)據(jù)
技術(shù)后果:
- 一旦緩存失效,基礎(chǔ)數(shù)據(jù)請(qǐng)求直接打數(shù)據(jù)庫
- 影響整個(gè)業(yè)務(wù)鏈條的正常訪問
(五)根本原因
1. Redis 只是緩存,并非數(shù)據(jù)庫防護(hù)墻
- Redis 的主要作用是加速數(shù)據(jù)訪問,減少數(shù)據(jù)庫壓力
- Redis 并不會(huì)阻止數(shù)據(jù)庫本身被訪問
- 一旦緩存未命中(Key 過期或被淘汰),請(qǐng)求就直接打數(shù)據(jù)庫
技術(shù)點(diǎn):緩存只是讀寫加速層,它不存儲(chǔ)業(yè)務(wù)邏輯約束,也不限制請(qǐng)求流量
2. 高并發(fā)請(qǐng)求集中在失效 Key 上
- 當(dāng)一個(gè)熱點(diǎn) Key 過期或被刪除,瞬間所有訪問這個(gè) Key 的請(qǐng)求都會(huì)落到數(shù)據(jù)庫
- 數(shù)據(jù)庫承受能力有限,如果瞬時(shí) QPS 超過數(shù)據(jù)庫峰值 → 查詢排隊(duì)
技術(shù)點(diǎn):
- Redis hit rate 高 → 大部分請(qǐng)求在緩存層就被攔截
- Key 失效瞬間 → 緩存失效窗口,hit rate 突然變低 → DB 瞬時(shí)壓力飆升
3. 數(shù)據(jù)庫無法承受大量并發(fā)請(qǐng)求
數(shù)據(jù)庫在高并發(fā)下可能出現(xiàn):
(1)CPU 飽和 → 查詢速度下降
(2)IO 瓶頸 → 磁盤或網(wǎng)絡(luò)訪問慢
(3)連接耗盡 → 數(shù)據(jù)庫拒絕新連接
(3)事務(wù)阻塞 → 并發(fā)寫操作阻塞其他請(qǐng)求
結(jié)果:接口響應(yīng)變慢、請(qǐng)求超時(shí),甚至數(shù)據(jù)庫宕機(jī)
技術(shù)點(diǎn):緩存擊穿不是 Redis 的問題,而是熱點(diǎn)數(shù)據(jù)失效 + 數(shù)據(jù)庫瞬時(shí)承載能力不足的系統(tǒng)問題
(六)解決策略
1. 熱點(diǎn) Key 永不過期 / 邏輯過期
思路:
- 對(duì)真正熱點(diǎn)的數(shù)據(jù),不設(shè)置 TTL,讓緩存一直存在
- 或者使用“邏輯過期”,即緩存中記錄一個(gè)過期時(shí)間,但讀取時(shí)仍然可以返回舊數(shù)據(jù),同時(shí)后臺(tái)異步刷新
技術(shù)實(shí)現(xiàn):
- 永不過期:SET key value 不設(shè)置 EX 參數(shù)
- 邏輯過期:緩存結(jié)構(gòu)如 {value: ..., expireTime: 1234567890}
- 讀取時(shí)判斷 expireTime 是否過期
- 如果過期,后臺(tái)線程異步更新緩存,用戶仍然能讀取舊值
適用場(chǎng)景:
熱門商品、排行榜、系統(tǒng)配置、常用字典數(shù)據(jù)
2. 互斥鎖 / 單線程加載
思路:
- 當(dāng)緩存失效時(shí),只有一個(gè)線程去加載數(shù)據(jù)庫,其它線程等待緩存更新,避免高并發(fā)同時(shí)打數(shù)據(jù)庫
技術(shù)實(shí)現(xiàn)(Java 示例):
String cache = redis.get(key);
if (cache == null) {
if (tryLock(key + "_lock")) { // 嘗試獲取鎖
String dbData = queryFromDB(); // 查詢數(shù)據(jù)庫
redis.set(key, dbData, 60); // 回寫緩存
unlock(key + "_lock"); // 釋放鎖
return dbData;
} else {
Thread.sleep(50); // 等待一段時(shí)間
return redis.get(key); // 重試讀取緩存
}
}
return cache;適用場(chǎng)景:
秒殺活動(dòng)、熱點(diǎn) Key 高并發(fā)訪問場(chǎng)景
3. 緩存預(yù)熱 + 定時(shí)刷新
思路:
- 系統(tǒng)啟動(dòng)或緩存即將過期時(shí)提前加載熱點(diǎn)數(shù)據(jù)到緩存
- 避免緩存失效瞬間出現(xiàn)大量請(qǐng)求落到數(shù)據(jù)庫
技術(shù)實(shí)現(xiàn):
- 緩存預(yù)熱:系統(tǒng)啟動(dòng)時(shí)讀取數(shù)據(jù)庫,將熱點(diǎn) Key 加入 Redis
- 定時(shí)刷新:使用定時(shí)任務(wù)或后臺(tái)線程,提前更新即將過期的 Key
適用場(chǎng)景:
- 系統(tǒng)啟動(dòng)后的熱門數(shù)據(jù)
- 高頻訪問的排行榜或統(tǒng)計(jì)數(shù)據(jù)
4. 降級(jí)處理 / 限流
思路:
- 當(dāng)緩存擊穿瞬間,可以對(duì)部分請(qǐng)求做降級(jí)或限流,保護(hù)數(shù)據(jù)庫
- 部分請(qǐng)求直接返回默認(rèn)值或提示稍后再試
技術(shù)實(shí)現(xiàn):
- 使用限流器(如令牌桶、漏桶算法)限制數(shù)據(jù)庫訪問頻率
- 對(duì)熱點(diǎn)查詢返回緩存的舊值或默認(rèn)值
- 結(jié)合互斥鎖或邏輯過期,提高系統(tǒng)容錯(cuò)能力
適用場(chǎng)景:
- 秒殺活動(dòng)、熱門接口請(qǐng)求暴增場(chǎng)景
- 保護(hù)數(shù)據(jù)庫穩(wěn)定,保證系統(tǒng)可用性
(七)優(yōu)化角度
1. 熱點(diǎn)識(shí)別
概念:先識(shí)別哪些 Key 是真正的熱點(diǎn)數(shù)據(jù)(訪問頻率高、壓力大的 Key),針對(duì)這些 Key 才做特殊處理。
具體做法:
(1)在 Redis 中記錄訪問頻率或使用監(jiān)控統(tǒng)計(jì)訪問量
(2)根據(jù)訪問量排序,識(shí)別訪問量大的 Key 為熱點(diǎn)
(3)對(duì)熱點(diǎn) Key 可采取“永不過期”或“邏輯過期 + 異步刷新”等策略
作用:
- 只針對(duì)真正的熱點(diǎn)做優(yōu)化,避免資源浪費(fèi)
- 降低緩存擊穿風(fēng)險(xiǎn)
2. TTL 差異化
概念:給不同 Key 設(shè)置不同過期時(shí)間,避免大量熱點(diǎn) Key 同時(shí)過期。
具體做法:
- 對(duì)普通 Key 設(shè)置短 TTL
- 對(duì)熱點(diǎn) Key 設(shè)置長 TTL 或邏輯過期
- 可以給相似熱點(diǎn) Key 設(shè)置錯(cuò)開 TTL,避免同時(shí)失效
作用:
- 避免多個(gè)熱點(diǎn) Key 同時(shí)過期 → 大量請(qǐng)求同時(shí)打數(shù)據(jù)庫
- 平滑系統(tǒng)壓力
3. 分布式鎖 / 單點(diǎn)加載
概念:緩存失效時(shí),保證只有一個(gè)請(qǐng)求去訪問數(shù)據(jù)庫加載數(shù)據(jù),其他請(qǐng)求等待或重試緩存。
具體做法:
- 使用 Redis 的 SETNX 或 Redisson 提供的分布式鎖
- 第一個(gè)請(qǐng)求獲取鎖去加載數(shù)據(jù)庫
- 其他請(qǐng)求等待鎖釋放或讀取緩存
作用:
- 避免高并發(fā)請(qǐng)求同時(shí)擊穿數(shù)據(jù)庫
- 控制數(shù)據(jù)庫瞬時(shí)壓力
示例流程:
請(qǐng)求1 → 獲取鎖 → 查詢 DB → 回寫緩存 → 釋放鎖 請(qǐng)求2 → 獲取鎖失敗 → 等待 / 重試緩存 請(qǐng)求3 → 同上
4. 邏輯過期 + 異步刷新
概念:緩存中存儲(chǔ)數(shù)據(jù)的邏輯過期時(shí)間,而不是直接讓 Key 過期。
具體做法:
(1)緩存結(jié)構(gòu):{value: ..., expireTime: timestamp}
(2)讀取時(shí)判斷 expireTime 是否過期
- 未過期 → 直接返回緩存
- 已過期 → 后臺(tái)線程異步刷新緩存,前端仍返回舊值
(3)異步刷新完成后更新緩存
作用:
- 用戶請(qǐng)求不會(huì)直接落到數(shù)據(jù)庫
- 避免緩存失效瞬間擊穿數(shù)據(jù)庫
- 保證系統(tǒng)高并發(fā)下可用性
(八)注意事項(xiàng)
1. 分布式系統(tǒng)注意點(diǎn)
- 在多節(jié)點(diǎn)或微服務(wù)環(huán)境下,如果采用 分布式鎖 或 邏輯過期刷新,需要保證跨節(jié)點(diǎn)的一致性。
- 可使用成熟的工具或框架實(shí)現(xiàn)分布式鎖,例如 Redisson、ZooKeeper 或 Etcd。
- 這樣可以避免多個(gè)節(jié)點(diǎn)同時(shí)刷新緩存,防止數(shù)據(jù)庫壓力再次集中。
2. 數(shù)據(jù)一致性問題
- 使用 邏輯過期 + 異步刷新 時(shí),可能會(huì)在短時(shí)間內(nèi)返回過期的舊數(shù)據(jù)(臟數(shù)據(jù))。
- 需要根據(jù)業(yè)務(wù)可容忍度判斷是否可以接受這種短暫的不一致,例如:排行榜、商品瀏覽量等統(tǒng)計(jì)類數(shù)據(jù)通常允許短暫延遲。
- 對(duì)于對(duì)實(shí)時(shí)性要求高的關(guān)鍵業(yè)務(wù),需額外設(shè)計(jì)一致性策略。
3. 限流/降級(jí)策略的組合使用
在高并發(fā)場(chǎng)景下,單獨(dú)的策略可能不足以完全保護(hù)數(shù)據(jù)庫。
推薦組合方案:邏輯過期 + 分布式鎖 + 限流/降級(jí)
這樣可以確保:
- 請(qǐng)求不會(huì)直接擊穿數(shù)據(jù)庫
- 緩存刷新有序
- 系統(tǒng)在瞬時(shí)高并發(fā)下仍保持可用性
二、緩存穿透
(一)概念
緩存穿透指的是 查詢一個(gè)根本不存在的數(shù)據(jù)時(shí),請(qǐng)求會(huì)繞過緩存直接打到數(shù)據(jù)庫,如果這種請(qǐng)求量很大,會(huì)導(dǎo)致數(shù)據(jù)庫壓力急劇增加。
- 核心:請(qǐng)求的數(shù)據(jù)在緩存和數(shù)據(jù)庫中都不存在
- 表現(xiàn):緩存永遠(yuǎn)無法命中,數(shù)據(jù)庫承受全部請(qǐng)求
請(qǐng)求數(shù)據(jù)A(不存在)
↓
Redis查詢,未命中
↓
直接訪問數(shù)據(jù)庫
↓
數(shù)據(jù)庫也沒有該數(shù)據(jù)
↓
返回結(jié)果給用戶
特點(diǎn):
- 數(shù)據(jù)不存在 → 每次請(qǐng)求都要查詢數(shù)據(jù)庫
- 緩存沒有命中 → 每次都落到數(shù)據(jù)庫
- 高并發(fā)下可能造成數(shù)據(jù)庫壓力過大
(二)觸發(fā)原因
1. 用戶惡意請(qǐng)求
- 惡意刷接口,隨機(jī)生成不存在的 ID 請(qǐng)求
- 例如:/product/999999999,數(shù)據(jù)庫中根本沒有
2. 程序缺陷或參數(shù)錯(cuò)誤
- 前端或接口調(diào)用傳錯(cuò)參數(shù),導(dǎo)致請(qǐng)求不存在的數(shù)據(jù)
- 例如:用戶傳了非法商品 ID 或拼寫錯(cuò)誤的關(guān)鍵字
3. 緩存未處理空結(jié)果
- 查詢不存在的數(shù)據(jù),緩存層沒有保存空對(duì)象
- 每次請(qǐng)求都走數(shù)據(jù)庫 → 穿透
(三)典型場(chǎng)景
1. 商品查詢接口
- 用戶請(qǐng)求不存在的商品 ID
- 沒有緩存空對(duì)象 → 每次都打數(shù)據(jù)庫
2. 用戶登錄或注冊(cè)校驗(yàn)接口
- 查詢不存在的用戶名或手機(jī)號(hào)
- 高并發(fā)時(shí)可能形成數(shù)據(jù)庫壓力
3. 通用搜索或統(tǒng)計(jì)接口
- 查詢歷史不存在的記錄或隨機(jī)關(guān)鍵字
- 數(shù)據(jù)庫承載能力下降
(四)可能后果
1. 數(shù)據(jù)庫壓力增加
- 大量不存在的數(shù)據(jù)請(qǐng)求直接落到數(shù)據(jù)庫
- CPU、IO 占用增加
2. 接口響應(yīng)變慢 / 超時(shí)
- 高并發(fā)下數(shù)據(jù)庫響應(yīng)慢,接口可能返回超時(shí)
3. 系統(tǒng)可用性降低
- 數(shù)據(jù)庫過載 → 其他正常請(qǐng)求也受影響
4. 潛在安全風(fēng)險(xiǎn)
- 惡意請(qǐng)求可能導(dǎo)致拒絕服務(wù)(DoS)攻擊
(五)解決策略
1. 緩存空對(duì)象(Null Cache)
- 將數(shù)據(jù)庫查詢不存在的數(shù)據(jù)也緩存起來(空對(duì)象或特殊標(biāo)記)
- 設(shè)置較短 TTL 避免緩存無限膨脹
示例:
String cache = redis.get(key);
if (cache != null) {
return cache.equals("NULL") ? null : cache;
} else {
String dbData = queryFromDB();
if (dbData == null) {
redis.set(key, "NULL", 60); // 緩存空對(duì)象
return null;
} else {
redis.set(key, dbData, 3600);
return dbData;
}
}2. 布隆過濾器(Bloom Filter)
- 在請(qǐng)求到達(dá)緩存/數(shù)據(jù)庫之前,用布隆過濾器快速判斷 key 是否存在
- 不存在的請(qǐng)求直接攔截,避免落到數(shù)據(jù)庫
特點(diǎn):
- 支持海量數(shù)據(jù)
- 允許少量誤判(存在概率誤判為存在,但不會(huì)漏判)
- 場(chǎng)景:熱門商品 ID、用戶 ID 等高頻接口
3. 接口層校驗(yàn) / 參數(shù)校驗(yàn)
- 對(duì)傳入請(qǐng)求參數(shù)做合法性校驗(yàn)
- 非法 ID、空 ID、格式錯(cuò)誤的請(qǐng)求直接拒絕
4. 限流和防刷策略
- 對(duì)接口增加限流、頻率限制
- 防止惡意請(qǐng)求或高并發(fā)重復(fù)查詢不存在數(shù)據(jù)
(六)進(jìn)一步優(yōu)化與注意事項(xiàng)
1. 分布式環(huán)境注意點(diǎn)
- 如果系統(tǒng)是多節(jié)點(diǎn)或微服務(wù)架構(gòu),需要保證布隆過濾器或緩存空對(duì)象在各節(jié)點(diǎn)的一致性。
- 可以使用 集中式布隆過濾器 或分布式緩存同步策略,避免不同節(jié)點(diǎn)出現(xiàn)數(shù)據(jù)不一致。
2. 空對(duì)象緩存策略優(yōu)化
- 緩存空對(duì)象時(shí)需要控制 TTL,避免占用過多緩存資源。
- 對(duì)于熱門但不存在的數(shù)據(jù),可以適當(dāng)加長 TTL;對(duì)于隨機(jī)或惡意請(qǐng)求的數(shù)據(jù),TTL 設(shè)置短一些即可。
- 結(jié)合日志監(jiān)控,發(fā)現(xiàn)頻繁穿透的 Key,可進(jìn)一步處理或封禁請(qǐng)求源。
3. 結(jié)合限流與防刷策略
在高并發(fā)或惡意請(qǐng)求場(chǎng)景,單靠緩存空對(duì)象或布隆過濾器可能不足。
可以使用 限流 + 防刷,例如:
- 限制接口每秒請(qǐng)求次數(shù)
- 對(duì)異常頻繁請(qǐng)求 IP 或用戶進(jìn)行封禁或驗(yàn)證碼驗(yàn)證
- 結(jié)合緩存策略可以更有效保護(hù)數(shù)據(jù)庫穩(wěn)定性。
4. 監(jiān)控與報(bào)警
- 對(duì)緩存命中率、數(shù)據(jù)庫查詢量進(jìn)行監(jiān)控
- 當(dāng)發(fā)現(xiàn)緩存命中率下降、數(shù)據(jù)庫異常增多時(shí),觸發(fā)告警
- 幫助運(yùn)維及時(shí)發(fā)現(xiàn)緩存穿透攻擊或異常請(qǐng)求
三、緩存雪崩
(一)概念
緩存雪崩指的是大量緩存同時(shí)失效,導(dǎo)致大量請(qǐng)求直接打到數(shù)據(jù)庫,使數(shù)據(jù)庫瞬間承受超高壓力,可能導(dǎo)致系統(tǒng)不可用。
- 核心:大量緩存同時(shí)過期或失效
- 表現(xiàn):數(shù)據(jù)庫壓力驟增,接口響應(yīng)延遲或失敗
流程示意:
大量熱點(diǎn)Key同時(shí)過期
↓
緩存全部未命中
↓
請(qǐng)求全部打到數(shù)據(jù)庫
↓
數(shù)據(jù)庫承受高壓
↓
接口響應(yīng)變慢或宕機(jī)
特點(diǎn):
- 大量 Key 同時(shí)失效 → 大量請(qǐng)求集中落到數(shù)據(jù)庫
- 高并發(fā)下數(shù)據(jù)庫無法承受 → 系統(tǒng)可能整體不可用
不同于緩存擊穿:緩存雪崩可能涉及 多個(gè) Key,而擊穿通常是 單個(gè)熱點(diǎn) Key
(二)觸發(fā)原因
1. 大量 Key TTL 相同
- 系統(tǒng)初始化時(shí)給緩存設(shè)置了統(tǒng)一過期時(shí)間,例如都 1 小時(shí)
- 到期瞬間,大量請(qǐng)求同時(shí)訪問數(shù)據(jù)庫
2. Redis 宕機(jī)或重啟
- Redis 服務(wù)不可用 → 緩存全部失效
- 所有請(qǐng)求直接落到數(shù)據(jù)庫
3. 緩存淘汰策略觸發(fā)
- 當(dāng) Redis 內(nèi)存不足,根據(jù) LRU/LFU 策略淘汰大量 Key
- 瞬時(shí)失效 → 請(qǐng)求直接訪問數(shù)據(jù)庫
(三)典型場(chǎng)景
1. 秒殺活動(dòng)或促銷活動(dòng)
- 活動(dòng)前預(yù)熱緩存,設(shè)置統(tǒng)一過期時(shí)間
- 活動(dòng)開始或 TTL 到期 → 大量商品緩存同時(shí)過期
- 大量請(qǐng)求直接打數(shù)據(jù)庫 → 宕機(jī)風(fēng)險(xiǎn)
2. 系統(tǒng)啟動(dòng)或 Redis 重啟
- 系統(tǒng)重啟或 Redis 重啟 → 緩存清空
- 熱門 Key 未預(yù)熱 → 請(qǐng)求直接落數(shù)據(jù)庫
3. 大規(guī)模緩存失效
- 一些批量刷新或緩存清理操作
- 例如定時(shí)清理排行榜、統(tǒng)計(jì)數(shù)據(jù)
- 多個(gè) Key 同時(shí)失效 → 請(qǐng)求瞬間集中
(四)可能后果
1. 數(shù)據(jù)庫瞬時(shí)壓力飆升
- CPU、IO、連接數(shù)暴漲
2. 接口響應(yīng)延遲或失敗
- 請(qǐng)求排隊(duì) → 用戶體驗(yàn)差
3. 系統(tǒng)可用性下降
- 多個(gè)業(yè)務(wù)模塊同時(shí)受影響 → 鏈?zhǔn)椒磻?yīng)
4. 觸發(fā)緩存擊穿或雪崩放大
- 一個(gè) Key 的高并發(fā)擊穿 + 大量 Key 同時(shí)過期 → 系統(tǒng)雪崩
(五)解決策略
1. 緩存過期時(shí)間錯(cuò)開 / 隨機(jī)化 TTL
- 給 Key TTL 增加隨機(jī)偏移量,避免大量 Key 同時(shí)過期
- 例如:設(shè)置 TTL = 3600 ± random(0~300) 秒
2. 緩存預(yù)熱(Cache Preload)
- 系統(tǒng)啟動(dòng)或緩存即將失效前,提前加載熱點(diǎn)數(shù)據(jù)到緩存
- 避免大量請(qǐng)求落到數(shù)據(jù)庫
3. 互斥鎖或單線程加載
- 當(dāng)緩存失效時(shí),控制只有一個(gè)請(qǐng)求訪問數(shù)據(jù)庫,其它請(qǐng)求等待
- 避免高并發(fā)直接打數(shù)據(jù)庫
4. 降級(jí)與限流
- 對(duì)部分請(qǐng)求返回默認(rèn)值或提示稍后重試
- 使用限流器控制訪問數(shù)據(jù)庫的速率
5. 多級(jí)緩存 / 本地緩存 + Redis
- 本地緩存存熱點(diǎn)數(shù)據(jù) → Redis 失效前可以命中本地緩存
- 降低對(duì) Redis 和數(shù)據(jù)庫瞬時(shí)壓力
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis過期Key刪除策略和內(nèi)存淘汰策略的實(shí)現(xiàn)
當(dāng)內(nèi)存使用達(dá)到上限,就無法存儲(chǔ)更多數(shù)據(jù)了,為了解決這個(gè)問題,Redis內(nèi)部會(huì)有兩套內(nèi)存回收的策略,過期Key刪除策略和內(nèi)存淘汰策略,本文就來詳細(xì)的介紹一下這兩種方法,感興趣的可以了解一下2024-02-02
Redis服務(wù)端主動(dòng)回收配置的使用小結(jié)
本文主要介紹了Redis服務(wù)端主動(dòng)回收配置的使用小結(jié),包括客戶端主動(dòng)回收、連接池配置、連接泄漏檢測(cè)及服務(wù)端策略設(shè)置,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-08-08
關(guān)于Redis數(shù)據(jù)持久化的概念介紹
Redis是內(nèi)存數(shù)據(jù)庫,數(shù)據(jù)都是存儲(chǔ)在內(nèi)存中,需要定期將Redis中的數(shù)據(jù)以某種形式(或命數(shù)據(jù)令)從內(nèi)存保存到硬盤,今天給大家分享Redis數(shù)據(jù)的持久化的概念介紹,需要的朋友參考下吧2021-08-08
深入理解Redis 延遲監(jiān)控的項(xiàng)目實(shí)踐
本文主要介紹了Redis 延遲監(jiān)控,它通過事件鉤子記錄和存儲(chǔ)時(shí)間序列數(shù)據(jù),幫助用戶精確回放和分析延遲事件,具有一定的參考價(jià)值,感興趣的可以了解一下2025-11-11
Redis內(nèi)存碎片率調(diào)優(yōu)處理方式
Redis集群因內(nèi)存碎片率超過1.5觸發(fā)告警,分析發(fā)現(xiàn)內(nèi)因與外因?qū)е聝?nèi)存碎片,內(nèi)因?yàn)椴僮飨到y(tǒng)內(nèi)存分配機(jī)制,外因?yàn)镽edis操作特性,使用Redis內(nèi)置內(nèi)存碎片清理機(jī)制可有效降低碎片率,但需注意可能影響性能,建議使用MEMORY命令診斷內(nèi)存使用情況,合理配置參數(shù)以優(yōu)化性能2024-09-09
異步redis隊(duì)列實(shí)現(xiàn) 數(shù)據(jù)入庫的方法
今天小編就為大家分享一篇異步redis隊(duì)列實(shí)現(xiàn) 數(shù)據(jù)入庫的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-10-10
Redis配置外網(wǎng)可訪問(redis遠(yuǎn)程連接不上)的方法
默認(rèn)情況下,當(dāng)我們?cè)诓渴鹆藃edis服務(wù)之后,redis本身默認(rèn)只允許本地訪問。Redis服務(wù)端只允許它所在服務(wù)器上的客戶端訪問,如果Redis服務(wù)端和Redis客戶端不在同一個(gè)機(jī)器上,就要進(jìn)行配置。2022-12-12

