緩存系列:緩存雪崩的解決思路
大家好,我是華仔。
上次我們討論了在分布式系統(tǒng)下的緩存架構(gòu)體系,從瀏覽器緩存到客戶端緩存,再到CDN緩存,再到反向代理緩存,再到本地緩存,再到分布式緩存。整個鏈路中有非常多的緩存。
在整個緩存鏈路,存在各種各樣的問題,常見的問題有緩存穿透、緩存擊穿、緩存雪崩、緩存數(shù)據(jù)一致性問題等。不常見的問題有緩存傾斜、緩存阻塞、緩存慢查詢、緩存主從一致性問題、緩存高可用、緩存故障發(fā)現(xiàn)與故障恢復(fù)、集群擴(kuò)容收縮、大Key熱Key等等。
今天我們就來聊聊:緩存雪崩
緩存雪崩,顧名思義,是緩存崩了。如果這樣理解的話,那就錯了,請跟我來一探究竟吧。
老規(guī)矩,先看一下本文大綱:
- 什么是緩存雪崩
- 緩存雪崩的痛點有哪些
- 緩存雪崩的解決思路
- 總結(jié)
什么是緩存雪崩
我們知道,緩存的工作原理是先從緩存中獲取數(shù)據(jù),如果有數(shù)據(jù)則直接返回給用戶,如果沒有數(shù)據(jù)則從慢速設(shè)備上讀取實際數(shù)據(jù)并且將數(shù)據(jù)放入緩存。就像這樣:
緩存里面的數(shù)據(jù)有很多,如果有一個key過期,那么就需要回溯查詢,如果這個key是熱點key,慢設(shè)備壓力劇增,有可能導(dǎo)致慢設(shè)備宕機(jī)。就像這樣:
這便是我們之前說的:緩存擊穿
那如果是很多key都過期了,那請求都會透過緩存層,直奔慢設(shè)備了,如果這些失效的key的請求之和很大,那么慢設(shè)備壓力劇增,有可能導(dǎo)致慢設(shè)備宕機(jī)。就像這樣:
這便是我們今天的主題:緩存雪崩
沒錯,從上面的含義其實已經(jīng)能夠理解出一個區(qū)別:
緩存擊穿強(qiáng)調(diào)單Key過期+高并發(fā);
緩存雪崩強(qiáng)調(diào)多key過期+高并發(fā)。
(所以,緩存雪崩不是緩存崩了,是一大片大片的緩存數(shù)據(jù)都在同一時間都失效了)
雪崩,實在是太可怕了。
緩存雪崩的痛點有哪些
- 熱點數(shù)據(jù)扎堆過期
- 緩存層瞬間透明化
- 慢設(shè)備層有被擊垮的風(fēng)險
大家猜想一下,為什么會瞬間有大量數(shù)據(jù)過期呢?
有兩個方向,其一是大量數(shù)據(jù)同時放入緩存+過期時間設(shè)置的時間是一致的;其二是大量數(shù)據(jù)放入緩存的時間點不一樣,但是過期時間是同一時間過期。
其一比較好理解,給大家舉幾個場景就更好了理解了,比如系統(tǒng)在啟動的時候或者每天定時的對大量數(shù)據(jù)進(jìn)行預(yù)熱,并且過期時間是一樣的。又或者是大促,商品在同一時刻開放,大量的用戶進(jìn)行不同商品的訪問,這些商品數(shù)據(jù)幾乎同時進(jìn)入緩存,并且過期時間是一樣的。
其二不太容易理解,給大家舉個場景就好了。比如有一個給用戶推送消息的需求,但是一天只允許推送一次,假設(shè)給張三同學(xué)早上8點推送,那么可以將這條數(shù)據(jù)放入緩存,過期時間為16小時,再次給張三推送的時候檢查緩存是否存在,緩存存在則不允許推送了,緩存不存在則允許推送。給李四同學(xué)下午14點推送了一條消息,那么給李四同學(xué)放緩存的數(shù)據(jù)過期時間應(yīng)該是10小時。這個場景就解釋了在不同的時間點放入的數(shù)據(jù),它們的過期時間不一樣,但是都是在同一時刻過期(在這個例子中是每天0點過期)。
緩存雪崩的解決思路
1、從上述的其一來看,是數(shù)據(jù)放入緩存的時間和過期時間一樣,所以最終大量數(shù)據(jù)同一時間過期。
所以,我們從這一點來看,我們可以改變數(shù)據(jù)放入緩存的的時間,也可以選擇修改數(shù)據(jù)的過期時間,讓過期時間不一致,最終的目的是讓數(shù)據(jù)分散在不同的時間點過期,從而減少數(shù)據(jù)庫的高并發(fā)壓力。很顯然,修改數(shù)據(jù)的過期時間更簡單一些,讓緩存時間在一定的區(qū)域隨機(jī)取值,很輕松就能解決了一個緩存雪崩的問題。
2、當(dāng)然了,問題的產(chǎn)生是數(shù)據(jù)過期了,所以還有一種解決方案是:讓你的數(shù)據(jù)永不過期!顯然,你的leader或者身為leader的你是不會這么玩的,這個方案基本不可行。原因是就算讓緩存數(shù)據(jù)在緩存永不過期,那難道緩存敢保證100%保證可用嗎?不敢,所以,你還是需要準(zhǔn)備planB,做好緩存宕機(jī)或者緩存數(shù)據(jù)不存在的備案。
3、既然是因為并發(fā)訪問導(dǎo)致,我們是不是可以由高并發(fā)轉(zhuǎn)換低并發(fā),稱之為互斥鎖,或者分布式鎖等,總之,加鎖來保證高并發(fā)轉(zhuǎn)換成低并發(fā)。
4、我們繼續(xù)分析,像這種熱點數(shù)據(jù),是不是應(yīng)該由熱點服務(wù)器去完成,對吧?我們應(yīng)該去做隔離機(jī)制,如果你有一套實時熱點發(fā)現(xiàn)系統(tǒng),再加上熱點流量自動遷移到熱點服務(wù)器,就算有這些有什么用,能解決問題嗎?答案是不能,因為熱點服務(wù)器仍然是需要防止緩存雪崩的,方案在上面已經(jīng)提到過了就不再贅述了。這里只是拋磚引玉,淺談環(huán)境隔離與實時熱點發(fā)現(xiàn)。
5、繼續(xù),既然是數(shù)據(jù)庫承受不住了,我們在知道問題的情況下,可以對數(shù)據(jù)做離散分布,讓它均勻地分布在我們的分布式數(shù)據(jù)庫中,同時對數(shù)據(jù)庫盡量的水平擴(kuò)容,常見的分庫分表策略有32庫32表,64庫64表,128庫128表......,這樣做的目的是讓單臺數(shù)據(jù)庫壓力變小,從而防止緩存雪崩。
6、繼續(xù)分析,我們從現(xiàn)象來看,是數(shù)據(jù)庫宕機(jī)了,原因是數(shù)據(jù)庫接受到的瞬間請求太多了,數(shù)據(jù)庫扛不住壓力所以就停止工作了。那我們是不是可以這么分析,如果我們提前知道數(shù)據(jù)庫能承受的最大閾值是多少,并且提前設(shè)置好數(shù)據(jù)庫的閾值或者服務(wù)的閾值,如果瞬間流量來了,我們把超過閾值的流量進(jìn)行排隊等待或者直接拒絕服務(wù),保證數(shù)據(jù)庫的壓力是不超過閾值的,是不是也能解決緩存雪崩所帶來的影響呢?
那么這里面有涉及到幾個數(shù)據(jù):數(shù)據(jù)庫的閾值從何得知、服務(wù)的閾值從何得知、如何設(shè)置數(shù)據(jù)庫或者服務(wù)的閾值。
答案是:數(shù)據(jù)的閾值應(yīng)該是壓測后得出,而設(shè)置閾值應(yīng)該是在網(wǎng)關(guān)層進(jìn)行限流處理,所以你需要有這樣的限流平臺。
對于壓測和網(wǎng)關(guān),我們后續(xù)會有專門的文章來討論,本期暫且不深入了,敬請期待??梢躁P(guān)注我的公中號:李哥技術(shù)
總結(jié)
其實緩存雪崩的理解很簡單,為什么說得這么復(fù)雜,原因很簡單,就是不想讓大家用背八股文一樣的方式去記憶,而是靠深入理解它的痛點然后逐步分析解決方案去記憶。
來總結(jié)一下吧。
概念:緩存雪崩指的是大片大片的緩存數(shù)據(jù)同時過期失效,再加上高并發(fā)的請求進(jìn)入到慢設(shè)備,慢設(shè)備壓力劇增,有可能導(dǎo)致慢設(shè)備宕機(jī),這便是緩存雪崩。
解決方案:
- 修改數(shù)據(jù)放入緩存的時間,或修改數(shù)據(jù)在緩存中的過期時間;
- 讓緩存數(shù)據(jù)永不過期;
- 互斥鎖,由高并發(fā)轉(zhuǎn)換成低并發(fā),保護(hù)DB;
- 熱點隔離,實時熱點發(fā)現(xiàn)系統(tǒng);
- 水平擴(kuò)容數(shù)據(jù)庫,壓力平攤,保護(hù)DB;
- 提前壓測,得出閾值,限流處理,保護(hù)服務(wù)與DB;
好了,本期緩存雪崩的解決思路就到這里了,感謝閱讀!