緩存穿透、緩存擊穿、緩存雪崩,這樣回答要滿分呀!
前言
大家好,我是田螺。
緩存穿透、緩存擊穿、緩存雪崩是經(jīng)典的老八股文啦,之前去面試一個(gè)銀行,就被問到啦,本文跟大家聊聊怎么回答哈~~
1.緩存穿透問題
先來看一個(gè)常見的緩存使用方式:
讀請(qǐng)求來了,先查下緩存,緩存有值命中,就直接返回;緩存沒命中,就去查數(shù)據(jù)庫,然后把數(shù)據(jù)庫的值更新到緩存,再返回。
圖片
1.1 什么是緩存穿透問題
緩存穿透:指查詢一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)需要從數(shù)據(jù)庫查詢,查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到數(shù)據(jù)庫去查詢,進(jìn)而給數(shù)據(jù)庫帶來壓力。
通俗點(diǎn)說,讀請(qǐng)求訪問時(shí),緩存和數(shù)據(jù)庫都沒有某個(gè)值,這樣就會(huì)導(dǎo)致每次對(duì)這個(gè)值的查詢請(qǐng)求都會(huì)穿透到數(shù)據(jù)庫,這就是緩存穿透。
1.2 緩存穿透產(chǎn)生原因
緩存穿透一般都是這幾種情況產(chǎn)生的:
- 業(yè)務(wù)邏輯設(shè)計(jì)不合理:比如大多數(shù)用戶都沒開守護(hù),但是你的每個(gè)請(qǐng)求都去查詢緩存,查詢某個(gè)userid有沒有開守護(hù)~
- 黑客非法請(qǐng)求攻擊:比如黑客故意捏造大量非法請(qǐng)求,以讀取不存在的業(yè)務(wù)數(shù)據(jù)。
- 數(shù)據(jù)生命周期管理問題:某些數(shù)據(jù)被刪除后,緩存沒有及時(shí)更新,導(dǎo)致后續(xù)查詢穿透。
如何避免緩存穿透呢? 一般有三種方法。
- 用戶請(qǐng)求進(jìn)行有效性檢查:它的核心思想是對(duì)請(qǐng)求參數(shù)進(jìn)行合法性校驗(yàn),提前過濾掉明顯無效的請(qǐng)求。(主要包括數(shù)據(jù)格式校驗(yàn)、數(shù)據(jù)范圍校驗(yàn)、權(quán)限校驗(yàn)等等)
- 緩存空值:如果查詢數(shù)據(jù)庫為空,我們可以給緩存設(shè)置個(gè)空值,或者一個(gè)特殊標(biāo)記的默認(rèn)值,設(shè)置一個(gè)較短的過期時(shí)間,避免頻繁訪問數(shù)據(jù)庫。(業(yè)務(wù)上比較常用,簡(jiǎn)單有效)
- 使用布隆過濾器:快速判斷數(shù)據(jù)是否存在。即一個(gè)查詢請(qǐng)求過來時(shí),先通過布隆過濾器判斷值是否存在,存在才繼續(xù)往下查。如果不存在,就不訪問數(shù)據(jù)庫啦~~
圖片
布隆過濾器原理:它由初始值為0的位圖數(shù)組和N個(gè)哈希函數(shù)組成。一個(gè)對(duì)一個(gè)key進(jìn)行N個(gè)hash算法獲取N個(gè)值,在比特?cái)?shù)組中將這N個(gè)值散列后設(shè)定為1,然后查的時(shí)候如果特定的這幾個(gè)位置都為1,那么布隆過濾器判斷該key存在,否則不存在。
2.緩存雪崩問題
緩存雪崩:在某個(gè)時(shí)間點(diǎn),大量緩存數(shù)據(jù)同時(shí)過期, 導(dǎo)致大量請(qǐng)求直接訪問數(shù)據(jù)庫,引起數(shù)據(jù)庫壓力過大甚至down機(jī)。
2.1 緩存雪崩常見原因
- 緩存設(shè)置了集中的過期時(shí)間:大量緩存數(shù)據(jù)設(shè)置了相同或者相似的過期時(shí)間,導(dǎo)致它們?cè)谕粫r(shí)間段內(nèi)集體過期。
- 緩存預(yù)熱不充分:系統(tǒng)啟動(dòng)時(shí)緩存數(shù)據(jù)加載不充分,導(dǎo)致大量請(qǐng)求直接訪問數(shù)據(jù)庫。
- 緩存服務(wù)器宕機(jī):redis集群中,多個(gè)節(jié)點(diǎn)同時(shí)宕機(jī),導(dǎo)致大量緩存數(shù)據(jù)不可用
常見一些經(jīng)典場(chǎng)景:促銷活動(dòng)結(jié)束(大量商品緩存同時(shí)失效)、或者定時(shí)任務(wù)觸發(fā)(比如凌晨批量更新緩存,固定過期時(shí)間觸發(fā)雪崩)
2.2 如何解決緩存雪崩的問題
通過分散過期時(shí)間,是解決緩存雪崩最簡(jiǎn)單有效的解決方案~~
可通過均勻設(shè)置過期時(shí)間解決,即讓過期時(shí)間相對(duì)離散一點(diǎn)。如采用一個(gè)較大固定值+一個(gè)較小的隨機(jī)值,1小時(shí)+0到100秒醬紫。
Redis 故障宕機(jī)也可能引起緩存雪奔。這就需要構(gòu)造Redis高可用集群啦。比如redis主從、哨兵模式、集群模式(Redis cluster)。
當(dāng)然,還有最后的防線,就是限流和降級(jí)~~
3. 緩存擊穿問題
緩存擊穿是指某個(gè)熱點(diǎn)數(shù)據(jù)在緩存中過期的同時(shí),大量并發(fā)請(qǐng)求訪問該數(shù)據(jù),導(dǎo)致這些請(qǐng)求直接訪問數(shù)據(jù)庫,造成數(shù)據(jù)庫壓力驟增。
緩存擊穿看著跟緩存雪崩有點(diǎn)像,其實(shí)它兩區(qū)別是:
- 緩存擊穿針對(duì)單個(gè)熱點(diǎn) Key,緩存雪崩針對(duì)大量Key或整個(gè)緩存服務(wù)
- 影響結(jié)果不一樣,緩存擊穿導(dǎo)致數(shù)據(jù)庫短期壓力劇增;緩存雪崩則可能導(dǎo)致數(shù)據(jù)庫被壓垮
3.1 緩存擊穿常見原因
- 高并發(fā)場(chǎng)景,比如秒殺活動(dòng)呀,熱點(diǎn)新聞等
- 管理員手動(dòng)誤清除:運(yùn)維人員誤刪或主動(dòng)清理某個(gè)熱點(diǎn)Key(如商品價(jià)格調(diào)整),刪除后突發(fā)流量訪問。
3.2 緩存擊穿的解決方案
常見的解決方案:
- 使用互斥鎖方案。緩存失效時(shí),不是立即去加載db數(shù)據(jù),而是先使用某些帶成功返回的原子操作命令,如(Redis的setnx)去操作,成功的時(shí)候,再去加載db數(shù)據(jù)庫數(shù)據(jù)和設(shè)置緩存。否則就去重試獲取緩存。
- “永不過期”,是指沒有設(shè)置過期時(shí)間,但是熱點(diǎn)數(shù)據(jù)快要過期時(shí),異步線程去更新和設(shè)置過期時(shí)間。
- 隨機(jī)過期時(shí)間,通過為熱點(diǎn)數(shù)據(jù)設(shè)置略有差異的過期時(shí)間,避免大量熱點(diǎn)數(shù)據(jù)同時(shí)失效