面試前必知Redis面試題—緩存雪崩+穿透+緩存與數(shù)據(jù)庫(kù)雙寫一致問題

今天來分享一下Redis幾道常見的面試題:

  • 如何解決緩存雪崩?

  • 如何解決緩存穿透牵现?

  • 如何保證緩存與數(shù)據(jù)庫(kù)雙寫時(shí)一致的問題橱野?

一修陡、緩存雪崩

1.1什么是緩存雪崩?

回顧一下我們?yōu)槭裁匆镁彺?Redis):

image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">為什么要緩存</figcaption>

現(xiàn)在有個(gè)問題可霎,如果我們的緩存掛掉了魄鸦,這意味著我們的全部請(qǐng)求都跑去數(shù)據(jù)庫(kù)了

image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">如果緩存掛掉了癣朗,全部請(qǐng)求跑去數(shù)據(jù)庫(kù)了</figcaption>

在前面學(xué)習(xí)我們都知道Redis不可能把所有的數(shù)據(jù)都緩存起來(內(nèi)存昂貴且有限)拾因,所以Redis需要對(duì)數(shù)據(jù)設(shè)置過期時(shí)間,并采用的是惰性刪除+定期刪除兩種策略對(duì)過期鍵刪除旷余。Redis對(duì)過期鍵的策略+持久化

如果緩存數(shù)據(jù)設(shè)置的過期時(shí)間是相同的绢记,并且Redis恰好將這部分?jǐn)?shù)據(jù)全部刪光了。這就會(huì)導(dǎo)致在這段時(shí)間內(nèi)正卧,這些緩存同時(shí)失效蠢熄,全部請(qǐng)求到數(shù)據(jù)庫(kù)中。

這就是緩存雪崩

  • Redis掛掉了炉旷,請(qǐng)求全部走數(shù)據(jù)庫(kù)签孔。

  • 對(duì)緩存數(shù)據(jù)設(shè)置相同的過期時(shí)間,導(dǎo)致某段時(shí)間內(nèi)緩存失效窘行,請(qǐng)求全部走數(shù)據(jù)庫(kù)饥追。

緩存雪崩如果發(fā)生了,很可能就把我們的數(shù)據(jù)庫(kù)搞垮罐盔,導(dǎo)致整個(gè)服務(wù)癱瘓判耕!

1.2如何解決緩存雪崩?

對(duì)于“對(duì)緩存數(shù)據(jù)設(shè)置相同的過期時(shí)間翘骂,導(dǎo)致某段時(shí)間內(nèi)緩存失效壁熄,請(qǐng)求全部走數(shù)據(jù)庫(kù)√季梗”這種情況草丧,非常好解決:

  • 解決方法:在緩存的時(shí)候給過期時(shí)間加上一個(gè)隨機(jī)值,這樣就會(huì)大幅度的減少緩存在同一時(shí)間過期莹桅。

對(duì)于“Redis掛掉了昌执,請(qǐng)求全部走數(shù)據(jù)庫(kù)”這種情況,我們可以有以下的思路:

  • 事發(fā)前:實(shí)現(xiàn)Redis的高可用(主從架構(gòu)+Sentinel 或者Redis Cluster)诈泼,盡量避免Redis掛掉這種情況發(fā)生懂拾。

  • 事發(fā)中:萬(wàn)一Redis真的掛了,我們可以設(shè)置本地緩存(ehcache)+限流(hystrix)铐达,盡量避免我們的數(shù)據(jù)庫(kù)被干掉(起碼能保證我們的服務(wù)還是能正常工作的)

  • 事發(fā)后:redis持久化岖赋,重啟后自動(dòng)從磁盤上加載數(shù)據(jù),快速恢復(fù)緩存數(shù)據(jù)瓮孙。

二唐断、緩存穿透

2.1什么是緩存穿透

比如选脊,我們有一張數(shù)據(jù)庫(kù)表,ID都是從1開始的(正數(shù)):

image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">隨便找了一張數(shù)據(jù)庫(kù)表</figcaption>

但是可能有黑客想把我的數(shù)據(jù)庫(kù)搞垮脸甘,每次請(qǐng)求的ID都是負(fù)數(shù)恳啥。這會(huì)導(dǎo)致我的緩存就沒用了,請(qǐng)求全部都找數(shù)據(jù)庫(kù)去了丹诀,但數(shù)據(jù)庫(kù)也沒有這個(gè)值啊钝的,所以每次都返回空出去。

緩存穿透是指查詢一個(gè)一定不存在的數(shù)據(jù)铆遭。由于緩存不命中硝桩,并且出于容錯(cuò)考慮,如果從數(shù)據(jù)庫(kù)查不到數(shù)據(jù)則不寫入緩存疚脐,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到數(shù)據(jù)庫(kù)去查詢,失去了緩存的意義邢疙。

image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">緩存穿透</figcaption>

這就是緩存穿透

  • 請(qǐng)求的數(shù)據(jù)在緩存大量不命中棍弄,導(dǎo)致請(qǐng)求走數(shù)據(jù)庫(kù)。

緩存穿透如果發(fā)生了疟游,也可能把我們的數(shù)據(jù)庫(kù)搞垮呼畸,導(dǎo)致整個(gè)服務(wù)癱瘓!

2.1如何解決緩存穿透颁虐?

解決緩存穿透也有兩種方案:

  • 由于請(qǐng)求的參數(shù)是不合法的(每次都請(qǐng)求不存在的參數(shù))蛮原,于是我們可以使用布隆過濾器(BloomFilter)或者壓縮filter提前攔截,不合法就不讓這個(gè)請(qǐng)求到數(shù)據(jù)庫(kù)層另绩!

  • 當(dāng)我們從數(shù)據(jù)庫(kù)找不到的時(shí)候儒陨,我們也將這個(gè)空對(duì)象設(shè)置到緩存里邊去。下次再請(qǐng)求的時(shí)候笋籽,就可以從緩存里邊獲取了蹦漠。

  • 這種情況我們一般會(huì)將空對(duì)象設(shè)置一個(gè)較短的過期時(shí)間

三车海、緩存與數(shù)據(jù)庫(kù)雙寫一致

3.1對(duì)于讀操作笛园,流程是這樣的

上面講緩存穿透的時(shí)候也提到了:如果從數(shù)據(jù)庫(kù)查不到數(shù)據(jù)則不寫入緩存。

一般我們對(duì)讀操作的時(shí)候有這么一個(gè)固定的套路

  • 如果我們的數(shù)據(jù)在緩存里邊有侍芝,那么就直接取緩存的研铆。

  • 如果緩存里沒有我們想要的數(shù)據(jù),我們會(huì)先去查詢數(shù)據(jù)庫(kù)州叠,然后將數(shù)據(jù)庫(kù)查出來的數(shù)據(jù)寫到緩存中棵红。

  • 最后將數(shù)據(jù)返回給請(qǐng)求

3.2什么是緩存與數(shù)據(jù)庫(kù)雙寫一致問題?

如果僅僅查詢的話咧栗,緩存的數(shù)據(jù)和數(shù)據(jù)庫(kù)的數(shù)據(jù)是沒問題的窄赋。但是哟冬,當(dāng)我們要更新時(shí)候呢?各種情況很可能就造成數(shù)據(jù)庫(kù)和緩存的數(shù)據(jù)不一致了忆绰。

  • 這里不一致指的是:數(shù)據(jù)庫(kù)的數(shù)據(jù)跟緩存的數(shù)據(jù)不一致
image
padding: 0px; max-width: 100%; 
box-sizing: border-box !important;
 word-wrap: break-word !important; l
ine-height: inherit; 
text-align: center; 
color: rgb(153, 153, 153); 
font-size: 0.7em;">數(shù)據(jù)庫(kù)和緩存的數(shù)據(jù)不一致</figcaption> 

從理論上說浩峡,只要我們?cè)O(shè)置了鍵的過期時(shí)間,我們就能保證緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)最終是一致的错敢。因?yàn)橹灰彺鏀?shù)據(jù)過期了翰灾,就會(huì)被刪除。隨后讀的時(shí)候稚茅,因?yàn)榫彺胬餂]有纸淮,就可以查數(shù)據(jù)庫(kù)的數(shù)據(jù),然后將數(shù)據(jù)庫(kù)查出來的數(shù)據(jù)寫入到緩存中亚享。

除了設(shè)置過期時(shí)間咽块,我們還需要做更多的措施來盡量避免數(shù)據(jù)庫(kù)與緩存處于不一致的情況發(fā)生。

3.3對(duì)于更新操作

一般來說欺税,執(zhí)行更新操作時(shí)侈沪,我們會(huì)有兩種選擇:

  • 先操作數(shù)據(jù)庫(kù),再操作緩存

  • 先操作緩存晚凿,再操作數(shù)據(jù)庫(kù)

首先亭罪,要明確的是,無(wú)論我們選擇哪個(gè)歼秽,我們都希望這兩個(gè)操作要么同時(shí)成功应役,要么同時(shí)失敗。所以燥筷,這會(huì)演變成一個(gè)分布式事務(wù)的問題箩祥。

所以,如果原子性被破壞了肆氓,可能會(huì)有以下的情況:

  • 操作數(shù)據(jù)庫(kù)成功了滥比,操作緩存失敗了

  • 操作緩存成功了做院,操作數(shù)據(jù)庫(kù)失敗了盲泛。

如果第一步已經(jīng)失敗了,我們直接返回Exception出去就好了键耕,第二步根本不會(huì)執(zhí)行寺滚。

下面我們具體來分析一下吧。

3.3.1操作緩存

操作緩存也有兩種方案:

  • 更新緩存

  • 刪除緩存

一般我們都是采取刪除緩存緩存策略的屈雄,原因如下:

  1. 高并發(fā)環(huán)境下村视,無(wú)論是先操作數(shù)據(jù)庫(kù)還是后操作數(shù)據(jù)庫(kù)而言,如果加上更新緩存酒奶,那就更加容易導(dǎo)致數(shù)據(jù)庫(kù)與緩存數(shù)據(jù)不一致問題蚁孔。(刪除緩存直接和簡(jiǎn)單很多)

  2. 如果每次更新了數(shù)據(jù)庫(kù)奶赔,都要更新緩存【這里指的是頻繁更新的場(chǎng)景,這會(huì)耗費(fèi)一定的性能】杠氢,倒不如直接刪除掉站刑。等再次讀取時(shí),緩存里沒有鼻百,那我到數(shù)據(jù)庫(kù)找绞旅,在數(shù)據(jù)庫(kù)找到再寫到緩存里邊(體現(xiàn)懶加載)

基于這兩點(diǎn),對(duì)于緩存在更新時(shí)而言温艇,都是建議執(zhí)行刪除操作因悲!

3.3.2先更新數(shù)據(jù)庫(kù),再刪除緩存

正常的情況是這樣的:

  • 先操作數(shù)據(jù)庫(kù)勺爱,成功晃琳;

  • 再刪除緩存,也成功琐鲁;

如果原子性被破壞了:

  • 第一步成功(操作數(shù)據(jù)庫(kù))卫旱,第二步失敗(刪除緩存),會(huì)導(dǎo)致數(shù)據(jù)庫(kù)里是新數(shù)據(jù)绣否,而緩存里是舊數(shù)據(jù)誊涯。

  • 如果第一步(操作數(shù)據(jù)庫(kù))就失敗了挡毅,我們可以直接返回錯(cuò)誤(Exception)蒜撮,不會(huì)出現(xiàn)數(shù)據(jù)不一致。

如果在高并發(fā)的場(chǎng)景下跪呈,出現(xiàn)數(shù)據(jù)庫(kù)與緩存數(shù)據(jù)不一致的概率特別低段磨,也不是沒有:

  • 緩存剛好失效

  • 線程A查詢數(shù)據(jù)庫(kù),得一個(gè)舊值

  • 線程B將新值寫入數(shù)據(jù)庫(kù)

  • 線程B刪除緩存

  • 線程A將查到的舊值寫入緩存

要達(dá)成上述情況耗绿,還是說一句概率特別低

因?yàn)檫@個(gè)條件需要發(fā)生在讀緩存時(shí)緩存失效苹支,而且并發(fā)著有一個(gè)寫操作。而實(shí)際上數(shù)據(jù)庫(kù)的寫操作會(huì)比讀操作慢得多误阻,而且還要鎖表债蜜,而讀操作必需在寫操作前進(jìn)入數(shù)據(jù)庫(kù)操作,而又要晚于寫操作更新緩存究反,所有的這些條件都具備的概率基本并不大寻定。

對(duì)于這種策略,其實(shí)是一種設(shè)計(jì)模式:Cache Aside Pattern

image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">先修改數(shù)據(jù)庫(kù)精耐,再刪除緩存</figcaption>

刪除緩存失敗的解決思路

  • 將需要?jiǎng)h除的key發(fā)送到消息隊(duì)列中

  • 自己消費(fèi)消息狼速,獲得需要?jiǎng)h除的key

  • 不斷重試刪除操作,直到成功

3.3.3先刪除緩存卦停,再更新數(shù)據(jù)庫(kù)

正常情況是這樣的:

  • 先刪除緩存向胡,成功恼蓬;

  • 再更新數(shù)據(jù)庫(kù),也成功僵芹;

如果原子性被破壞了:

  • 第一步成功(刪除緩存)处硬,第二步失敗(更新數(shù)據(jù)庫(kù)),數(shù)據(jù)庫(kù)和緩存的數(shù)據(jù)還是一致的淮捆。

  • 如果第一步(刪除緩存)就失敗了郁油,我們可以直接返回錯(cuò)誤(Exception),數(shù)據(jù)庫(kù)和緩存的數(shù)據(jù)還是一致的攀痊。

看起來是很美好桐腌,但是我們?cè)诓l(fā)場(chǎng)景下分析一下,就知道還是有問題的了:

  • 線程A刪除了緩存

  • 線程B查詢苟径,發(fā)現(xiàn)緩存已不存在

  • 線程B去數(shù)據(jù)庫(kù)查詢得到舊值

  • 線程B將舊值寫入緩存

  • 線程A將新值寫入數(shù)據(jù)庫(kù)

所以也會(huì)導(dǎo)致數(shù)據(jù)庫(kù)和緩存不一致的問題案站。

并發(fā)下解決數(shù)據(jù)庫(kù)與緩存不一致的思路

  • 將刪除緩存、修改數(shù)據(jù)庫(kù)棘街、讀取緩存等的操作積壓到隊(duì)列里邊蟆盐,實(shí)現(xiàn)串行化
image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; line-height: inherit; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">將操作積壓到隊(duì)列中</figcaption>

3.4對(duì)比兩種策略

我們可以發(fā)現(xiàn)遭殉,兩種策略各自有優(yōu)缺點(diǎn):

  • 先刪除緩存石挂,再更新數(shù)據(jù)庫(kù)

  • 在高并發(fā)下表現(xiàn)不如意,在原子性被破壞時(shí)表現(xiàn)優(yōu)異

  • 先更新數(shù)據(jù)庫(kù)险污,再刪除緩存(Cache Aside Pattern設(shè)計(jì)模式)

  • 在高并發(fā)下表現(xiàn)優(yōu)異痹愚,在原子性被破壞時(shí)表現(xiàn)不如意#總結(jié)

總結(jié)【精華】

針對(duì)于上面的Redis面試題我總結(jié)出了互聯(lián)網(wǎng)公司java程序員面試涉及到的絕大部分面試題及答案做成了文檔和架構(gòu)視頻資料免費(fèi)分享給大家(還包括Dubbo、Redis蛔糯、Netty拯腮、zookeeper、Spring cloud蚁飒、分布式动壤、高并發(fā)等架構(gòu)技術(shù)資料),希望能幫助到您面試前的復(fù)習(xí)且找到一個(gè)好的工作淮逻,也節(jié)省大家在網(wǎng)上搜索資料的時(shí)間來學(xué)習(xí)琼懊,也可以關(guān)注我一下以后會(huì)有更多干貨分享。

資料領(lǐng)取方式:

私人QQ群:536172545點(diǎn)擊鏈接加入群聊【互聯(lián)網(wǎng)java高級(jí)架構(gòu)】:https://jq.qq.com/?_wv=1027&k=54yx0LY

image

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末爬早,一起剝皮案震驚了整個(gè)濱河市哼丈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凸椿,老刑警劉巖削祈,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡髓抑,警方通過查閱死者的電腦和手機(jī)咙崎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吨拍,“玉大人褪猛,你說我怎么就攤上這事「危” “怎么了伊滋?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)队秩。 經(jīng)常有香客問我笑旺,道長(zhǎng),這世上最難降的妖魔是什么馍资? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任筒主,我火速辦了婚禮,結(jié)果婚禮上鸟蟹,老公的妹妹穿的比我還像新娘乌妙。我一直安慰自己,他們只是感情好建钥,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布藤韵。 她就那樣靜靜地躺著,像睡著了一般熊经。 火紅的嫁衣襯著肌膚如雪泽艘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天奈搜,我揣著相機(jī)與錄音悉盆,去河邊找鬼盯荤。 笑死馋吗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秋秤。 我是一名探鬼主播宏粤,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼灼卢!你這毒婦竟也來了绍哎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鞋真,失蹤者是張志新(化名)和其女友劉穎崇堰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡海诲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年繁莹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片特幔。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咨演,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蚯斯,到底是詐尸還是另有隱情薄风,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布拍嵌,位于F島的核電站遭赂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏横辆。R本人自食惡果不足惜嵌牺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望龄糊。 院中可真熱鬧逆粹,春花似錦、人聲如沸炫惩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)他嚷。三九已至蹋绽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筋蓖,已是汗流浹背卸耘。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粘咖,地道東北人蚣抗。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像瓮下,于是被迫代替她去往敵國(guó)和親翰铡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 今天來分享一下Redis幾道常見的面試題: 1.如何解決緩存雪崩讽坏? 2.如何解決緩存穿透锭魔? 3.如何保證緩存與數(shù)據(jù)...
    Java資訊庫(kù)閱讀 2,772評(píng)論 0 8
  • 一、緩存雪崩 1.1什么是緩存雪崩路呜? 回顧一下我們?yōu)槭裁匆镁彺?Redis): 現(xiàn)在有個(gè)問題迷捧,如果我們的緩存掛掉...
    Java架構(gòu)_師閱讀 320評(píng)論 0 1
  • SQLite Distinct 關(guān)鍵字 SQLite 的 DISTINCT 關(guān)鍵字與 SELECT 語(yǔ)句一起使用织咧,...
    木易林1閱讀 613評(píng)論 0 0
  • 花落半卷殘紅淚,柳下垂漠秋,人未睡烦感。 孤燈對(duì)影心憔悴,月如舊膛堤,廣宮寒手趣。 一別萬(wàn)里思故園,雁已去肥荔,人未還绿渣。 扶琴當(dāng)空彈,...
    李瀟寒閱讀 163評(píng)論 0 0
  • 我就像一座孤島燕耿, 飄蕩在寬闊的海洋中符, 沒有人與之開懷暢談, 總是蜷縮在一個(gè)冰冷的角落誉帅, 不是我故作冷漠淀散, 是人心太...
    汪小瑞閱讀 216評(píng)論 0 0