緩存擊穿完整講解 + 防御方案
一、什么是緩存擊穿(Cache Breakdown)?
定義:
某個(gè)「熱點(diǎn)Key」非常重要,訪問(wèn)量極高;
當(dāng)它 剛好過(guò)期的那一刻,大量請(qǐng)求同時(shí)訪問(wèn)該Key,由于緩存失效,會(huì) 瞬間全部打到數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)壓力驟增,甚至宕機(jī)。
二、緩存擊穿與其他問(wèn)題的區(qū)別
| 問(wèn)題類型 | 觸發(fā)條件 | 表現(xiàn) | 解決方向 |
|---|---|---|---|
| 緩存穿透 | 請(qǐng)求不存在的數(shù)據(jù)(數(shù)據(jù)庫(kù)也無(wú)) | 每次都查DB | 加布隆過(guò)濾器或空值緩存 |
| 緩存擊穿 | 熱點(diǎn)Key過(guò)期 | 一瞬間DB被打爆 | 加鎖、熱點(diǎn)Key永不過(guò)期 |
| 緩存雪崩 | 大量Key同時(shí)過(guò)期 | DB壓力突增 | 隨機(jī)過(guò)期時(shí)間 + 限流 |
三、緩存擊穿的防御方案
方案一:互斥鎖(Mutex Lock)
思路:
當(dāng)緩存失效時(shí),只有一個(gè)請(qǐng)求能去查數(shù)據(jù)庫(kù),其余請(qǐng)求等待。
適合「高并發(fā)下的熱點(diǎn)Key」。
實(shí)現(xiàn)示意(偽代碼):
String value = redis.get("product:1001");
if (value == null) {
// 嘗試獲取分布式鎖
if (tryLock("lock:product:1001")) {
// double check 避免重復(fù)查詢
value = redis.get("product:1001");
if (value == null) {
value = db.query("SELECT * FROM product WHERE id=1001");
redis.set("product:1001", value, 60);
}
unlock("lock:product:1001");
} else {
// 其他線程短暫休眠后重試
Thread.sleep(50);
value = redis.get("product:1001");
}
}
return value;
常用命令:
SET lock:product:1001 1 NX EX 5
NX:僅當(dāng)鎖不存在時(shí)設(shè)置 EX:自動(dòng)過(guò)期防死鎖方案二:熱點(diǎn) Key 永不過(guò)期 + 后臺(tái)異步更新
思路:
對(duì)極熱點(diǎn)數(shù)據(jù)(如排行榜、商品詳情)——不要讓它自然過(guò)期,而是定時(shí)刷新。
做法:
- 設(shè)置 Key 永不過(guò)期;
- 使用定時(shí)任務(wù)或消息隊(duì)列定期更新內(nèi)容;
- 或在請(qǐng)求線程中異步刷新:
// 異步刷新策略
if (System.currentTimeMillis() - cache.getUpdateTime("hotKey") > 10分鐘) {
threadPool.submit(() -> refreshHotKeyFromDB());
}
優(yōu)點(diǎn):
- 不會(huì)發(fā)生“過(guò)期瞬間擊穿”
- 適合讀多寫少、穩(wěn)定熱點(diǎn)數(shù)據(jù)
方案三:邏輯過(guò)期(雙層時(shí)間機(jī)制)
思路:
緩存中設(shè)置一個(gè)邏輯過(guò)期時(shí)間,不立即刪除數(shù)據(jù),而是由后臺(tái)線程更新。
{
"data": {...},
"expireTime": "2025-10-28 14:00:00"
}
邏輯:
if (now < expireTime) {
return cache.data; // 直接返回舊值
} else {
// 異步線程去更新DB + 緩存
refreshAsync();
return cache.data; // 先返回舊數(shù)據(jù),保證服務(wù)穩(wěn)定
}
優(yōu)點(diǎn):
- 用戶始終有數(shù)據(jù)返回,不會(huì)訪問(wèn)DB暴增
- 類似“后臺(tái)熱更新”
方案四:多級(jí)緩存(本地 + Redis)
在應(yīng)用層增加一層 本地緩存(如 Caffeine/Guava),
Redis 過(guò)期時(shí)也能頂一會(huì)兒,進(jìn)一步防止瞬間擊穿。
四、實(shí)際項(xiàng)目最佳實(shí)踐推薦
| 場(chǎng)景 | 推薦方案 |
|---|---|
| 普通熱點(diǎn)Key(商品詳情) | 互斥鎖 + 雙查機(jī)制 |
| 極高熱度Key(首頁(yè)配置、排行榜) | 永不過(guò)期 + 定時(shí)刷新 |
| 高QPS系統(tǒng)(上億訪問(wèn)) | 邏輯過(guò)期 + 異步刷新 + 本地緩存 |
| 分布式環(huán)境 | 使用 Redisson 或 Redis 原生鎖 |

