緩存穿透、擊穿、雪崩等問題及方案

緩存問題總結(jié)

前言

通常應(yīng)用中會使用數(shù)據(jù)庫來作為數(shù)據(jù)存儲,但是數(shù)據(jù)庫面向磁盤,磁盤的讀寫速度比較慢,不合適處理高并發(fā)的應(yīng)用場景,為了避免高并發(fā)場景下瞬間大量訪問DB導(dǎo)致數(shù)據(jù)庫系統(tǒng)癱瘓的問題,我們通常會使用緩存來提高系統(tǒng)支持高并發(fā)的能力。緩存一般都是基于內(nèi)存的數(shù)據(jù)庫,讀寫效率相比于磁盤讀寫都有大幅提升,但引入緩存后相應(yīng)也會引入一些緩存相關(guān)的問題。

緩存問題

  • 緩存穿透
  • 緩存擊穿
  • 緩存血崩
  • 緩存溢出
  • 數(shù)據(jù)丟失

下面我們以redis為例,來分析這些問題并給出對應(yīng)的解決方案。

問題分析

緩存穿透

緩存穿透指的是數(shù)據(jù)源(通常是DB)中,沒有key對應(yīng)的數(shù)據(jù)源,因此請求這類不存在的key,在緩存中獲取不到的話就需要直接請求數(shù)據(jù)源,請求并發(fā)量大的話就會給數(shù)據(jù)源造成壓力和風(fēng)險(xiǎn)。

針對這類問題,有兩個常用的解決方案:

1.即使查詢數(shù)據(jù)源沒有該key對應(yīng)的值,也在緩存中緩存該key,并設(shè)置空的value值。需要注意的是,必須給這種key設(shè)置一個短的過期時(shí)間,在這段時(shí)間內(nèi)數(shù)據(jù)源新增了這個key對應(yīng)的記錄但是獲取不到的情況。由此可見,該方案存在一個問題就是新增的記錄可能存在不能立即生效的問題。

2.第二種方案是使用布隆過濾器,將可能的key值數(shù)據(jù)取哈希存儲到一個bitmap中,通過判斷key值是否在bitmap內(nèi)來避免向數(shù)據(jù)源請求不存在的記錄。

緩存擊穿

緩存擊穿和緩存穿透不同,緩存穿透是請求不存在key記錄,而緩存擊穿請求的key在數(shù)據(jù)源中是有對應(yīng)的記錄的。對于熱點(diǎn)數(shù)據(jù)的key,如果剛好在緩存過期的時(shí)間后有大量并發(fā)請求,就會給數(shù)據(jù)源造成服務(wù)崩潰風(fēng)險(xiǎn)。

針對這一問題,通常的方案是加互斥鎖,只有獲取鎖的線程可以請求數(shù)據(jù)源,其他請求可以等待重試獲取緩存。

對于redis來說,可以通過SETNX操作來設(shè)置一個互斥key來實(shí)現(xiàn)互斥鎖,設(shè)置成功則代表成功獲取鎖。需要注意的是需要給互斥key來設(shè)置一個過期時(shí)間,避免死鎖問題。

此外,也可以設(shè)置熱點(diǎn)數(shù)據(jù)不過期來解決這類問題。

緩存雪崩

緩存擊穿是針對某一個key過期時(shí)的并發(fā)問題,而緩存雪崩是緩存服務(wù)器重啟或者大量緩存集中在一個時(shí)間段過期,導(dǎo)致大量并發(fā)請求直接打到數(shù)據(jù)源,造成數(shù)據(jù)源服務(wù)崩潰。

緩存雪崩的幾個解決方案:

  1. 采用隨機(jī)的過期時(shí)間。可以在設(shè)置緩存過期時(shí)間時(shí),盡量分散各個key的過期時(shí)間避免集中過期的場景
  2. 使用鎖或者隊(duì)列。通過鎖或者隊(duì)列來避免所有請求直接請求數(shù)據(jù)庫。這種會導(dǎo)致線程阻塞,可能影響用戶體驗(yàn)。
  3. 緩存標(biāo)記。通過記錄緩存數(shù)據(jù)是否過期,如果過期則通知專門的線程來處理實(shí)際key的更新。

緩存溢出

緩存使用的是內(nèi)存資源,相比于磁盤存儲來說可以緩存的數(shù)據(jù)有限的。緩存溢出是指緩存的數(shù)據(jù)達(dá)到上限,無法緩存更多的數(shù)據(jù)。

這種問題的解決方案通常是給緩存設(shè)置一定的淘汰策略,一般使用LRU(Least Recently Used)。最近最少使用的key會被優(yōu)先淘汰。

數(shù)據(jù)丟失

緩存數(shù)據(jù)在內(nèi)存中,如果緩存服務(wù)器宕機(jī)或者重啟,內(nèi)存中的數(shù)據(jù)就會丟失。

針對這一問題,主要依賴于緩存服務(wù)的持久化。redis提供了兩種數(shù)據(jù)持久化的方案,一種是RDB,一種是AOF。

RDB是在指定的時(shí)間間隔內(nèi)生成數(shù)據(jù)集的時(shí)間點(diǎn)快照,是一個非常緊湊的文件,適用于災(zāi)難恢復(fù),同時(shí)數(shù)據(jù)備份時(shí)只需要分配一個子進(jìn)程來處理數(shù)據(jù)保存工作,父進(jìn)程無需執(zhí)行磁盤IO操作,可以最大化Redis的性能。

AOF的話可以讓Redis非常耐久,盡可能短的減少數(shù)據(jù)丟失問題。但是備份文件體積要大于RDB,性能及恢復(fù)效率上不如RDB。

轉(zhuǎn)載請注明出處,如有錯誤的地方請留言給我更正,謝謝!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容