漫話:如何給女朋友解釋什么是緩存穿透、緩存擊穿、緩存雪崩?

周末在家面試,和候選人聊到Redis的問(wèn)題,于是問(wèn)了他一個(gè)問(wèn)題:你知道緩存穿透、緩存擊穿和緩存雪崩嗎?他們之間的區(qū)別是什么?分別怎么解決嗎?
面試結(jié)束后,女朋友好像有很多問(wèn)號(hào),于是來(lái)問(wèn)我。






要把這個(gè)問(wèn)題講清楚,先舉個(gè)例子。
一個(gè)女孩子去門(mén)店買口紅,到了門(mén)店之后被告知她想要的那個(gè)色號(hào)已經(jīng)沒(méi)有了。于是她要求店員去問(wèn)總部還有沒(méi)有貨??偛堪l(fā)現(xiàn)這個(gè)色號(hào)也沒(méi)有了,于是女孩子就離開(kāi)了。
過(guò)了一會(huì)另一個(gè)女孩子又來(lái)了,也想要購(gòu)買同一個(gè)色號(hào),店員就又總部問(wèn)了一次。如此反復(fù)。
女孩子買口紅不僅需要門(mén)店幫忙查詢,還需要總部也進(jìn)行盤(pán)貨。類似這種情況,在緩存領(lǐng)域有一個(gè)類似的概念叫做緩存穿透。

緩存穿透是指緩存服務(wù)器中沒(méi)有緩存數(shù)據(jù),數(shù)據(jù)庫(kù)中也沒(méi)有符合條件的數(shù)據(jù),導(dǎo)致業(yè)務(wù)系統(tǒng)每次都繞過(guò)緩存服務(wù)器查詢下游的數(shù)據(jù)庫(kù),緩存服務(wù)器完全失去了其應(yīng)用的作用。




緩存空值
解決多次詢問(wèn)總部的方法比較簡(jiǎn)單,如果口紅門(mén)店在幫第一個(gè)女孩子查詢之后,就記錄下來(lái)這個(gè)色號(hào)已經(jīng)沒(méi)有了,下次其他女孩再來(lái)問(wèn)這個(gè)色號(hào)的時(shí)候,直接告訴她沒(méi)貨了。
這樣就可以避免每次都驚動(dòng)總部了。
在緩存中,之所以會(huì)發(fā)生穿透,就是因?yàn)榫彺鏇](méi)有對(duì)那些不存在的值得Key緩存下來(lái),從而導(dǎo)致每次查詢都要請(qǐng)求到數(shù)據(jù)庫(kù)。
那么我們就可以為這些key對(duì)應(yīng)的值設(shè)置為null并放到緩存中,這樣再出現(xiàn)查詢這個(gè)key 的請(qǐng)求的時(shí)候,直接返回null即可 。
但是還需要注意的就是需要有一個(gè)失效時(shí)間,因?yàn)槿绻辉O(shè)置失效的話,如果哪天總部有貨了,門(mén)店還是當(dāng)做沒(méi)貨的話,就會(huì)影響銷量了。
BloomFilter
很多時(shí)候,緩存穿透是因?yàn)橛泻芏鄲阂饬髁康恼?qǐng)求,這些請(qǐng)求可能隨機(jī)生成很多Key來(lái)請(qǐng)求查詢,這些肯定在緩存和數(shù)據(jù)庫(kù)中都沒(méi)有,那就很容易導(dǎo)致緩存穿透。
針對(duì)類似的情況,可以使用一個(gè)過(guò)濾器。
比如如果有一群人經(jīng)常來(lái)門(mén)店問(wèn)一些根本不存在的色號(hào),比如五彩斑斕的黑,這些色號(hào)該品牌根本沒(méi)生產(chǎn)過(guò)的話,店員就可以直接告訴顧客不存在就行了,也不需要驚動(dòng)總部。
在緩存穿透防治上常用的技術(shù)是布隆過(guò)濾器(Bloom Filter)。
布隆過(guò)濾器是一種比較巧妙的概率性數(shù)據(jù)結(jié)構(gòu),它可以告訴你數(shù)據(jù)一定不存在或可能存在,相比Map、Set、List等傳統(tǒng)數(shù)據(jù)結(jié)構(gòu)它占用內(nèi)存少、結(jié)構(gòu)更高效。
對(duì)于緩存穿透,我們可以將查詢的數(shù)據(jù)條件都哈希到一個(gè)足夠大的布隆過(guò)濾器中,用戶發(fā)送的請(qǐng)求會(huì)先被布隆過(guò)濾器攔截,一定不存在的數(shù)據(jù)就直接攔截返回了,從而避免下一步對(duì)數(shù)據(jù)庫(kù)的壓力。




有一種比較特殊的情況,那就是如果某一個(gè)熱門(mén)色號(hào)的口紅剛好賣完了,這時(shí)候有很多顧客同時(shí)來(lái)咨詢要購(gòu)買這個(gè)色號(hào),那么門(mén)店內(nèi)的多個(gè)售貨員可能分別給總部打電話咨詢是否有存貨。
或者如果有多家門(mén)店同時(shí)賣完了,那么總部接收到的咨詢量就會(huì)劇增。類似這種情況,在緩存領(lǐng)域有一個(gè)類似的概念叫做緩存擊穿。

緩存擊穿是指當(dāng)某一key的緩存過(guò)期時(shí)大并發(fā)量的請(qǐng)求同時(shí)訪問(wèn)此key,瞬間擊穿緩存服務(wù)器直接訪問(wèn)數(shù)據(jù)庫(kù),讓數(shù)據(jù)庫(kù)處于負(fù)載的情況。




異步定時(shí)更新
如果提前知道某一個(gè)色號(hào)比較暢銷的話,那就可以定時(shí)的咨詢總部是否還有存貨,定時(shí)的更新庫(kù)存情況就可以避免上面這種情況了。
在緩存處理上,同理,比如某一個(gè)熱點(diǎn)數(shù)據(jù)的過(guò)期時(shí)間是1小時(shí),那么每59分鐘,通過(guò)定時(shí)任務(wù)去更新這個(gè)熱點(diǎn)key,并重新設(shè)置其過(guò)期時(shí)間。
還有一種解決辦法,那就是如果很多顧客咨詢的是同一個(gè)色號(hào)的口紅,那么就先處理第一個(gè)用戶的咨詢,其他同樣請(qǐng)求的顧客先排隊(duì)等待。一直到店員從總部那里獲取到最新的庫(kù)存信息后,就可以安排其他人繼續(xù)購(gòu)買了。
在緩存處理上,通常使用一個(gè)互斥鎖來(lái)解決緩存擊穿的問(wèn)題。簡(jiǎn)單來(lái)說(shuō)就是當(dāng)Redis中根據(jù)key獲得的value值為空時(shí),先鎖上,然后從數(shù)據(jù)庫(kù)加載,加載完畢,釋放鎖。若其他線程也在請(qǐng)求該key時(shí),發(fā)現(xiàn)獲取鎖失敗,則先阻塞。





如果門(mén)店內(nèi)的多個(gè)色號(hào)的口紅同時(shí)售罄了,并且門(mén)店在這個(gè)時(shí)間點(diǎn)剛好也不知道總部有沒(méi)有庫(kù)存了,這時(shí)候如果有大量顧客來(lái)到門(mén)店購(gòu)物的話,就會(huì)有更多的咨詢電話打到總部那里。
或者是門(mén)店突然出現(xiàn)問(wèn)題了,不能提供服務(wù)了,很多顧客就可能自己打電話到總部咨詢庫(kù)存情況。類似這種情況,在緩存領(lǐng)域有一個(gè)類似的概念叫做緩存雪崩。

緩存雪崩是指當(dāng)大量緩存同時(shí)過(guò)期或緩存服務(wù)宕機(jī),所有請(qǐng)求的都直接訪問(wèn)數(shù)據(jù)庫(kù),造成數(shù)據(jù)庫(kù)高負(fù)載,影響性能,甚至數(shù)據(jù)庫(kù)宕機(jī)。




不同的過(guò)期時(shí)間
為了避免緩存雪崩,門(mén)店可以考慮給不同的色號(hào)的口紅預(yù)留不同的庫(kù)存,并且采用不同的頻率咨詢總部庫(kù)存情況,更新到門(mén)店中。這樣就可以避免突然同一個(gè)時(shí)間點(diǎn)所有色號(hào)都售罄。
為了避免大量的緩存在同一時(shí)間過(guò)期,可以把不同的key過(guò)期時(shí)間設(shè)置成不同的, 并且通過(guò)定時(shí)刷新的方式更新過(guò)期時(shí)間。
集群
為了避免門(mén)店出問(wèn)題導(dǎo)致大量顧客直接打電話到總部,可以考慮開(kāi)更多的門(mén)店,將用戶分流到多個(gè)店鋪中。
類似的,在緩存雪崩問(wèn)題防治上面,一個(gè)比較典型的技術(shù)就是采用集群方式部署,使用集群可以避免服務(wù)單點(diǎn)故障。





關(guān)于作者:漫話編程,是一個(gè)通過(guò)漫畫(huà)+音頻的形式講解枯燥的編程知識(shí)的公眾號(hào)。致力于讓編程變得更有樂(lè)趣。
推薦閱讀:
喜歡我可以給我設(shè)為星標(biāo)哦


