探討生產(chǎn)環(huán)境下緩存雪崩的幾種場景及解決方案
緩存我們經(jīng)常使用,但是有時候我們卻會忽略緩存中的一些問題。我們將從生產(chǎn)環(huán)境的應(yīng)用的角度读存,去考慮需要注意的一些異常情況,特別的是在高并發(fā)的場景下呕屎,如何讓我們的緩存在提供高性能支持的同時让簿,去保證數(shù)據(jù)的準(zhǔn)確性,還有系統(tǒng)的穩(wěn)定性秀睛。
那么首先我們來看第一個問題尔当,我們看這張圖這里,這里我們引入的緩存的目的蹂安,就是用來幫助數(shù)據(jù)庫去擋掉大部分的讀請求椭迎,從而提升讀請求的響應(yīng)速度和并發(fā)能力,但是假如有一段時間田盈,由于種種原因畜号,這個緩存的數(shù)據(jù)不在了,那這個時候允瞧,這些讀請求全部都直接落到數(shù)據(jù)庫上面來简软,那如果這個時候并發(fā)量很大的話,就很有可能會把數(shù)據(jù)庫給壓垮述暂,那數(shù)據(jù)庫一垮基本上整個應(yīng)用都會被拖垮了痹升,更嚴(yán)重的話會造成一系列的連鎖反應(yīng),會影響到上下游系統(tǒng)畦韭。
生產(chǎn)環(huán)節(jié)出現(xiàn)緩存雪崩的幾種情況
那么我們總結(jié)一下這個問題就是:由于緩存數(shù)據(jù)失效(或不存在)疼蛾,導(dǎo)致大量讀請求直接訪問數(shù)據(jù)庫,把數(shù)據(jù)庫甚至應(yīng)用拖垮艺配。這個就是緩存雪崩問題察郁。那么我們可以看到這里問題的關(guān)鍵點衍慎,在于大量的緩存數(shù)據(jù)失效(或不存在),一般在生產(chǎn)環(huán)節(jié)中绳锅,主要有這幾種情況,可能會導(dǎo)致引起緩存雪崩問題:
情況一:
第一種情況可能是我們本身就沒有進(jìn)行提前預(yù)設(shè)置緩存酝掩,或者說有設(shè)置緩存鳞芙,但是寫入redis 的數(shù)據(jù)還沒來的及持久化,redis服務(wù)異常重啟期虾,那么這種情況下就可能會導(dǎo)致緩存數(shù)據(jù)丟失原朝。雖然說Redis提供了持久化機(jī)制,但它的兩種持久化模式镶苞,RDB和AOF喳坠,都沒辦法百分之百保證數(shù)據(jù)不丟失,實際上在實戰(zhàn)項目中茂蚓,很多時候為了減少對中間件的依賴壕鹉,為了降低運(yùn)維成本,或者為了提升Redis性能等等這些因素的考慮聋涨,很多系統(tǒng)都是不開啟Redis持久化機(jī)制的晾浴,那么這樣當(dāng)Redis發(fā)生重啟的話,緩存數(shù)據(jù)就全部清空了牍白。
情況二:
還有一種情況就是提前設(shè)置了緩存脊凰,但是呢緩存的過期時間設(shè)置過于集中,導(dǎo)致大批數(shù)據(jù)同時過期茂腥,所以我們在使用redis的時候呢也不得不考慮到這種情況的產(chǎn)生狸涌。就拿一年一度的雙十一購物節(jié)來說,假如馬上就要到雙十一零點最岗,很快就會迎來一波搶購帕胆,這波商品時間比較集中的放入了緩存,假設(shè)緩存一個小時般渡。那么到了凌晨一點鐘的時候惶楼,這批商品的緩存就都過期了。而對這批商品的訪問查詢诊杆,都落到了數(shù)據(jù)庫上歼捐,對于數(shù)據(jù)庫而言,就會產(chǎn)生周期性的壓力波峰晨汹,如果沒有一個好的處理方案豹储,可能在緩存失效的一瞬間,數(shù)據(jù)庫就扛不住壓力掛掉了淘这,進(jìn)而導(dǎo)致其它關(guān)聯(lián)的系統(tǒng)被拖累剥扣,最終導(dǎo)致整個系統(tǒng)崩潰巩剖,這種情況就是我們常說的緩存雪崩,想象下這種情況如果發(fā)生在雙十一會產(chǎn)生多么嚴(yán)重的影響钠怯。所以我們就得提前針對這種情況進(jìn)行思考設(shè)計佳魔。
情況三:
最后還有一種情況就是,我們都知道為了保證較高的性價比晦炊,緩存的空間容量必然要小于后端數(shù)據(jù)庫的數(shù)據(jù)總量鞠鲜,隨著要緩存的數(shù)據(jù)量越來越大,緩存空間就不可避免的會被寫滿断国。這個時候redis就會有一個緩存數(shù)據(jù)的淘汰機(jī)制贤姆,如果我們這個緩存淘汰機(jī)制設(shè)置得不是很合理就會大面積的淘汰掉正在使用的緩存,就會導(dǎo)致上面說的問題稳衬。
redis的緩存淘汰策略是指在Redis用于緩存的內(nèi)存不足時, 怎么處理
這里我們看下redis的兩個參數(shù)霞捡,我們可以通過設(shè)置maxmemory參數(shù)來設(shè)置內(nèi)存的最大使用量(配置) 同時來配置maxmemory-policy參數(shù):選擇對應(yīng)的內(nèi)存淘汰規(guī)則(配置), 當(dāng)內(nèi)存不夠用時, 會設(shè)置的內(nèi)存淘汰規(guī)則
其中在Redis 中有如下淘汰規(guī)則
規(guī)則 | 規(guī)則說明 |
---|---|
noeviction | 當(dāng)內(nèi)存不足以容納新寫入的數(shù)據(jù)時, 新寫入操作會報錯 |
allkeys-lru | 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時, 在鍵空間中, 移除最近最少使用的key |
allkeys-random | 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時, 在鍵空間中, 隨機(jī)移除某個key |
volatile-lru | 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時, 在設(shè)置了過期時間的鍵空間中, 移除最近最少使用的key |
allkeys-random | 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時, 在鍵空間中, 隨機(jī)移除某個key |
volatile-ttl | 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時, 在設(shè)置了過期時間的鍵空間中, 有更早過期時間的key優(yōu)先移除 |
那針對這種情況,我們可以結(jié)合項目的實際情況薄疚,通過指定合適的淘汰規(guī)則來避免有效的緩存數(shù)據(jù)丟失碧信,那么這個也只能稍微緩解一下,如果應(yīng)用中需要緩存的數(shù)據(jù)量非常大街夭,這個時候可以通過擴(kuò)大集群的部署規(guī)模音婶,來增加整個緩存組件的容量。
處理緩存雪崩的幾種解決方案
好那么上面就是三種主要的緩存失效的容易導(dǎo)致緩存雪崩的情況莱坎。
接下來我們來看一下常見的幾種解決緩存雪崩的方案:
首先結(jié)合業(yè)務(wù)的特點和場景衣式,從業(yè)務(wù)角度出發(fā),我們來看一下有哪些優(yōu)化手段 :
針對上面提到的緩存集中失效這個場景檐什,我們可以采用這樣的思路來緩解:
分散緩存失效時間
- 分散緩存失效時間碴卧。首先我們可以采取不同分類商品,緩存不同周期乃正。在同一分類中的商品住册,加上一個隨機(jī)因子。這樣能盡可能
分散緩存過期時間
瓮具,而且荧飞,熱門類目的商品緩存時間長一些,冷門類目的商品緩存時間短一些
名党,也能節(jié)省緩存服務(wù)的資源叹阔。
熱門數(shù)據(jù)不設(shè)置過期時間
- 熱門數(shù)據(jù)不設(shè)置過期時間。我們可以針對一些熱門商戶和熱門商品的數(shù)據(jù)传睹,也就是系統(tǒng)中最熱門的數(shù)據(jù)耳幢,設(shè)置為數(shù)據(jù)永不過期。這樣可這樣可以保證這部分請求量很大的數(shù)據(jù),一直能夠從緩存中去獲取數(shù)據(jù)
提前預(yù)熱緩存數(shù)據(jù)
-
還有一個策略睛藻,就是提前預(yù)熱緩存數(shù)據(jù)启上。什么叫緩存預(yù)熱,緩存預(yù)熱就是在系統(tǒng)啟動之后店印,或者系統(tǒng)運(yùn)行期間定期地將一些緩存數(shù)據(jù)直接加載到緩存系統(tǒng)冈在,這樣就可以避免等到用戶請求的時候再去查詢數(shù)據(jù)庫,然后再將數(shù)據(jù)回寫到緩存按摘。那么這種策略包券,除了適合前面提到的系統(tǒng)中最熱那一部分?jǐn)?shù)據(jù),也適合當(dāng)系統(tǒng)有營銷活動的時候院峡,去提前預(yù)熱相關(guān)的數(shù)據(jù)兴使,避免活動一開始的時候系宜,瞬間涌進(jìn)來的流量把系統(tǒng)沖垮照激。
image.png
那么緩存預(yù)熱的思路一般是這樣的:
當(dāng)數(shù)據(jù)量不大的時候,我們可以在工程啟動的時候盹牧,就進(jìn)行加載緩存動作俩垃;如果數(shù)據(jù)量比較大,那可以在運(yùn)行期間通過定時任務(wù)腳本汰寓,去進(jìn)行緩存的刷新口柳;重點呢是優(yōu)先保證熱點數(shù)據(jù)能夠提前加載到緩存。
好那這幾個就是結(jié)合業(yè)務(wù)場景有滑,從業(yè)務(wù)角度出發(fā)去優(yōu)化的策略跃闹,但是光靠這些策略只能起到緩解的作用,還是不足以完全保證我們系統(tǒng)穩(wěn)定毛好,我們還是需要通過技術(shù)手段來進(jìn)行保證望艺,那么除了上面我們提到的通過擴(kuò)大集群規(guī)模去解決容量不夠的問題,我們接下來主要看一下針對緩存失效的情況肌访,如何通過技術(shù)手段來防止系統(tǒng)雪崩問題
首先我們可以對數(shù)據(jù)庫訪問增加限流的處理 找默,來保護(hù)我們的數(shù)據(jù)庫,保護(hù)我們這個系統(tǒng)的核心資源吼驶。數(shù)據(jù)庫它跟緩存組件不一樣惩激,它并不擅長應(yīng)對高并發(fā)的場景,它所能承載的并發(fā)量蟹演,是遠(yuǎn)小于緩存中間件的风钻, 那如果把訪問緩存的請求全部懟到數(shù)據(jù)庫,分分鐘就把數(shù)據(jù)庫搞垮了酒请,通過限流讓系統(tǒng)響應(yīng)慢一點魄咕,總歸比直接把系統(tǒng)拖垮好一些。
還有一種方式蚌父,我們可以進(jìn)行緩存降級哮兰。那么緩存降級是指緩存失效或緩存服務(wù)器掛掉的情況下毛萌,不去訪問數(shù)據(jù)庫,直接返回默認(rèn)的數(shù)據(jù)喝滞,從而避免數(shù)據(jù)庫遭受巨大壓力阁将,當(dāng)然降級一般是對用戶體驗有損的,所以盡量減少降級對于業(yè)務(wù)的影響程度右遭。
好了做盅,通過上面說的這些方法,基本上可以避免緩存雪崩問題窘哈。謝謝大家吹榴。