快收藏!一個(gè)技巧從此不再搞混緩存穿透和緩存擊穿
在 Redis 中有兩個(gè)定義:一個(gè)緩存擊穿、一個(gè)緩存穿透,因?yàn)槎叩拿直容^像,因此很容易就搞混了。但本文會(huì)給你提供一個(gè)記憶的小技巧,幫你徹底區(qū)分二者的定義。
在講這個(gè)技巧之前,我們先來了解一下二者的區(qū)別。
1.定義與區(qū)別
- 緩存穿透(Cache Penetration):緩存穿透是指查詢的數(shù)據(jù)既不在緩存中,也不在數(shù)據(jù)庫中,但用戶仍然頻繁請(qǐng)求該數(shù)據(jù),導(dǎo)致請(qǐng)求直接穿透到數(shù)據(jù)庫,增加數(shù)據(jù)庫壓力。
a.核心問題:請(qǐng)求的數(shù)據(jù)根本不存在,但請(qǐng)求量很大,導(dǎo)致數(shù)據(jù)庫被無效查詢。
- 緩存擊穿(Cache Breakdown):緩存擊穿是指 熱點(diǎn)數(shù)據(jù)的緩存失效,大量并發(fā)請(qǐng)求同時(shí)查詢?cè)摂?shù)據(jù),導(dǎo)致請(qǐng)求直接沖擊數(shù)據(jù)庫,增加數(shù)據(jù)庫壓力。
a.核心問題:緩存中的數(shù)據(jù)失效,但數(shù)據(jù)庫中有對(duì)應(yīng)的數(shù)據(jù),請(qǐng)求量集中導(dǎo)致數(shù)據(jù)庫壓力驟增。
2.常見場(chǎng)景
- 緩存穿透:
a.用戶請(qǐng)求不存在的 ID(如負(fù)數(shù) ID 或非法字符)。
b.惡意攻擊者故意請(qǐng)求不存在的數(shù)據(jù)。
c.示例:請(qǐng)求用戶 ID 為 -1 或不存在的用戶信息。
- 緩存擊穿:
a.熱點(diǎn)數(shù)據(jù)(如熱門商品信息、熱門新聞)的緩存過期。
b.大量用戶同時(shí)請(qǐng)求該熱點(diǎn)數(shù)據(jù)。
c.示例:促銷活動(dòng)中的熱門商品信息突然失效。
3. 解決方案
(1)緩存穿透的解決方案
布隆過濾器(Bloom Filter):在緩存層前加一層布隆過濾器,預(yù)存所有合法 Key 的哈希值。請(qǐng)求到達(dá)時(shí),先檢查布隆過濾器:
- 如果不存在,直接攔截請(qǐng)求,返回空。
- 如果存在,再查詢緩存或數(shù)據(jù)庫。
- 優(yōu)點(diǎn):內(nèi)存占用少,能有效攔截不存在的請(qǐng)求。
- 缺點(diǎn):可能存在誤判,需要合理設(shè)置參數(shù)。
緩存空值(Cache Null):對(duì)查詢結(jié)果為空的 Key,緩存一個(gè) Null 值,避免重復(fù)穿透。
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡單,能有效減少數(shù)據(jù)庫壓力。
- 缺點(diǎn):可能會(huì)占用額外的緩存空間。
參數(shù)校驗(yàn):在查詢緩存之前,先對(duì)請(qǐng)求的參數(shù)進(jìn)行合法性檢查,如過濾非法字符、判斷參數(shù)范圍等,對(duì)于明顯錯(cuò)誤的參數(shù),直接攔截返回。
(2)緩存擊穿的解決方案
互斥鎖(Mutex Lock):當(dāng)緩存失效時(shí),通過分布式鎖讓一個(gè)線程重建緩存,其他線程等待鎖釋放后重試。
- 優(yōu)點(diǎn):能有效避免多個(gè)線程同時(shí)查詢數(shù)據(jù)庫。
- 缺點(diǎn):實(shí)現(xiàn)復(fù)雜,可能會(huì)影響性能。
永不過期(Logical Expiration):對(duì)熱點(diǎn) Key 設(shè)置物理永不過期,通過后臺(tái)異步線程定期更新緩存,保證數(shù)據(jù)新鮮度。
- 優(yōu)點(diǎn):避免緩存失效導(dǎo)致的數(shù)據(jù)庫壓力。
- 缺點(diǎn):需要額外的邏輯來管理緩存更新。
熔斷降級(jí):在緩存失效期間,啟用降級(jí)策略(如返回默認(rèn)值或靜態(tài)頁面),保護(hù)數(shù)據(jù)庫。
- 優(yōu)點(diǎn):能有效緩解數(shù)據(jù)庫壓力。
- 缺點(diǎn):用戶體驗(yàn)可能受影響。
4.對(duì)比
問題 | 定義 | 常見場(chǎng)景 | 解決方案 |
緩存穿透 | 請(qǐng)求的數(shù)據(jù)既不在緩存中,也不在數(shù)據(jù)庫中,但請(qǐng)求量很大,導(dǎo)致數(shù)據(jù)庫壓力增大 | 非法請(qǐng)求、惡意攻擊 | 布隆過濾器、緩存空值、參數(shù)校驗(yàn) |
緩存擊穿 | 熱點(diǎn)數(shù)據(jù)的緩存失效,大量并發(fā)請(qǐng)求直接沖擊數(shù)據(jù)庫 | 熱點(diǎn)數(shù)據(jù)失效、高并發(fā)場(chǎng)景 | 互斥鎖、永不過期、熔斷降級(jí) |
通過理解它們的定義、場(chǎng)景和解決方案,你可以更清晰地區(qū)分緩存穿透和緩存擊穿,并在實(shí)際開發(fā)中選擇合適的解決方法。
5.記憶秘訣
- 緩存擊穿:核心是熱點(diǎn)數(shù)據(jù)失效 -> 解決方案是重建熱點(diǎn)數(shù)據(jù)。
- 緩存穿透:核心是 Redis 和 MySQL 都沒有數(shù)據(jù) -> 解決方案是攔截?zé)o效請(qǐng)求。
因此,我們可以認(rèn)為:
- 緩存擊穿 -> 正常的數(shù)據(jù)失效引發(fā)的問題。
- 緩存穿透 -> 非正常的數(shù)據(jù)訪問引發(fā)的問題。
就像警察叔叔審訊犯人一樣,我們可以用“擊穿犯罪嫌疑人的心里防線”,但不能用“穿透犯罪嫌疑的心里防線”,所以,擊穿是“正義之詞”,而穿透是“非正義之詞”,例如,你這點(diǎn)小心思,我還看不“透”,“透”這個(gè)詞通常是用來描述不好的事情的,因此我們可以使用這個(gè)技巧來徹底區(qū)分緩存擊穿和緩存穿透了,如下圖所示:
小結(jié)
緩存擊穿和緩存穿透是 Redis 中兩個(gè)常見的高頻面試問題,但又很容易搞混二者的定義,我們通過學(xué)習(xí)本文的內(nèi)容,相信可以徹底的區(qū)分二者的定義。