面試官:談關(guān)于緩存穿透+擊穿+雪崩,熱點(diǎn)數(shù)據(jù)失效問(wèn)題的解決方案

1.我們使用緩存時(shí)的業(yè)務(wù)流程大概為:

當(dāng)我們查詢一條數(shù)據(jù)時(shí),先去查詢緩存,如果緩存有就直接返回,如果沒(méi)有就去查詢數(shù)據(jù)庫(kù),然后返回。這種情況下就可能出現(xiàn)下面的一些現(xiàn)象。

2.緩存穿透

2.1什么是緩存穿透

緩存穿透是指查詢一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)被動(dòng)寫的,并且出于容錯(cuò)考慮,如果從存儲(chǔ)層查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到存儲(chǔ)層去查詢,失去了緩存的意義。在流量大時(shí),可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應(yīng)用,這就是漏洞。

2.2緩存穿透帶來(lái)的問(wèn)題

試想一下,如果有黑客對(duì)你的系統(tǒng)進(jìn)行攻擊,拿一個(gè)不存在的id去查詢數(shù)據(jù),會(huì)產(chǎn)生大量的請(qǐng)求到你的數(shù)據(jù)庫(kù)去查詢,可能會(huì)導(dǎo)致你的數(shù)據(jù)庫(kù)由于壓力過(guò)大而宕掉。

2.3解決的辦法

2.3.1緩存空值

之所以會(huì)發(fā)生穿透,就是因?yàn)榫彺嬷袥](méi)有儲(chǔ)存這些空數(shù)據(jù)的key。從而導(dǎo)致每次查詢都到數(shù)據(jù)庫(kù)去了。

那么我們就可以為這些key對(duì)應(yīng)的值設(shè)置為null丟到緩存里面去。后面出現(xiàn)查詢這個(gè)key的請(qǐng)求的時(shí)候直接返回null。

這樣就不用再到數(shù)據(jù)庫(kù)中去走一圈了,但是別忘了設(shè)置過(guò)期時(shí)間。

緩存空對(duì)象會(huì)有兩個(gè)問(wèn)題:

第一,空值做了緩存,意味著緩存層中存了更多的鍵,需要更多的內(nèi)存空間 ( 如果是攻擊,問(wèn)題更嚴(yán)重 ),比較有效的方法是針對(duì)這類數(shù)據(jù)設(shè)置一個(gè)較短的過(guò)期時(shí)間,讓其自動(dòng)剔除。

第二,緩存層和存儲(chǔ)層的數(shù)據(jù)會(huì)有一段時(shí)間窗口的不一致,可能會(huì)對(duì)業(yè)務(wù)有一定影響。例如過(guò)期時(shí)間設(shè)置為 5分鐘,如果此時(shí)存儲(chǔ)層添加了這個(gè)數(shù)據(jù),那此段時(shí)間就會(huì)出現(xiàn)緩存層和存儲(chǔ)層數(shù)據(jù)的不一致,此時(shí)可以利用消息系統(tǒng)或者其他方式清除掉緩存層中的空對(duì)象。

2.3.2用布隆過(guò)濾器BloomFilter

BloomFilter類似于一個(gè)hbase set用來(lái)判斷某個(gè)元素(key)是否存在于某個(gè)集合中。

這種方式在大數(shù)據(jù)場(chǎng)景應(yīng)用比較多,比如Hbase中使用它去判斷數(shù)據(jù)是否在磁盤上。還有在爬蟲場(chǎng)景判斷url是否已經(jīng)被爬取過(guò)。

這種方案可以加在第一種方案中,在緩存之前加一層BloomFilter,在查詢的時(shí)候先去BloomFilter去查詢key是否存在,如果不存在就直接返回,存在再去查緩存-------->差數(shù)據(jù)庫(kù)。

流程圖如下:

2.4如何選擇

針對(duì)于一些惡意攻擊,攻擊帶來(lái)大量key是不存在的,那么我們采用第一種方案就會(huì)緩存大量不存在的數(shù)據(jù)。此時(shí)我們采用第一種方案就不合適了,我們完全可以先使用第二種方案過(guò)濾掉這些key。

針對(duì)這些key異常多,請(qǐng)求多,重復(fù)率比較低的數(shù)據(jù),我們就沒(méi)有必要進(jìn)行緩存,使用第二種方案直接過(guò)濾掉。

而對(duì)于空數(shù)據(jù)的key有限的,重復(fù)率比較高的,我們則可以采用第一種方式進(jìn)行緩存。

3.緩存擊穿

3.1什么是緩存擊穿

緩存擊穿是我們使用緩存可能遇到的第二個(gè)問(wèn)題。

在平時(shí)高并發(fā)的系統(tǒng)中,大量的請(qǐng)求同時(shí)查詢一個(gè)key時(shí),此時(shí)這個(gè)key正好失效了,就會(huì)導(dǎo)致大量的請(qǐng)求都打到數(shù)據(jù)庫(kù)上面去,這種現(xiàn)象我們稱為緩存擊穿。

3.2會(huì)帶來(lái)什么問(wèn)題

會(huì)造成某一時(shí)刻數(shù)據(jù)請(qǐng)求量過(guò)大,壓力劇增。

3.3如何解決

上面現(xiàn)象是多個(gè)線程同時(shí)去查詢數(shù)據(jù)庫(kù)的這一條數(shù)據(jù),那么我們可以在第一個(gè)查詢數(shù)據(jù)的請(qǐng)求上使用一個(gè)互斥鎖來(lái)鎖住它。(如果是單機(jī),可以用synchronized或者lock來(lái)處理,如果是分布式環(huán)境可以用分布式鎖就可以了(分布式鎖,可以用memcache的add, redis的setnx, zookeeper的添加節(jié)點(diǎn)操作))

其他線程走到這一步拿不到鎖就等著,等待第一個(gè)線程查詢到了數(shù)據(jù),然后做緩存。后面的線程進(jìn)來(lái)發(fā)現(xiàn)已經(jīng)有了緩存,就直接走緩存。

4.緩存雪崩

4.1什么是緩存雪崩

緩存雪崩的情況是指:當(dāng)某一時(shí)刻發(fā)生大規(guī)模的緩存失效的情況,比如你的緩存服務(wù)宕機(jī)了,會(huì)有大量的請(qǐng)求進(jìn)來(lái)直接打到數(shù)據(jù)庫(kù)上面,結(jié)果就是數(shù)據(jù)庫(kù)掛掉。

4.2解決辦法

4.2.1雪崩前:使用集群緩存,保證緩存服務(wù)的高可用

這種方案就是在發(fā)生雪崩前對(duì)緩存集群,實(shí)現(xiàn)高可用,如果是使用Redis,可以使用(主從 + 哨兵),Redis Cluster來(lái)避免Redis全盤崩潰的情況。

4.2.2雪崩中:ehcache本地緩存 + Hystrix限流 & 降級(jí),避免MySQl被打死

使用ehcache本地緩存的目的也是考慮Redis Cluster完全不可用的時(shí)候,ehcache本地緩存還能夠支撐一陣。

使用Hystrix進(jìn)行限流 & 降級(jí),比如一秒來(lái)了5000個(gè)請(qǐng)求,我們可以設(shè)置假設(shè)一秒只能有2000個(gè)請(qǐng)求可以通過(guò)這個(gè)組件,那么其他剩余的3000請(qǐng)求就會(huì)走限流邏輯。

然后去調(diào)用我們自己開發(fā)的降級(jí)組件(降級(jí)),比如設(shè)置的一些默認(rèn)值等等之類的。以此來(lái)保護(hù)最后的MySQl不會(huì)被大量的請(qǐng)求打死。

4.2.3雪崩后:開啟Redis持久化,盡快恢復(fù)緩存集群。

5.解決熱點(diǎn)數(shù)據(jù)集中失效問(wèn)題

我們?cè)谠O(shè)置緩存的時(shí)候,一般會(huì)給緩存設(shè)置一個(gè)失效的時(shí)間,過(guò)了這個(gè)時(shí)間,緩存就失效了。

對(duì)于一些熱點(diǎn)數(shù)據(jù)來(lái)說(shuō),當(dāng)緩存失效后會(huì)存在大量的請(qǐng)求到數(shù)據(jù)庫(kù)上來(lái),從而可能導(dǎo)致數(shù)據(jù)庫(kù)崩潰的情況。

5.1解決辦法

5.1.1設(shè)置不同的失效時(shí)間

為了避免這些熱點(diǎn)數(shù)據(jù)集體失效,那么我們?cè)谠O(shè)置緩存過(guò)期時(shí)間的時(shí)侯,讓他們失效的時(shí)間錯(cuò)開。比如我們可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值。

5.1.2互斥鎖

結(jié)合上面的擊穿情況,在第一個(gè)請(qǐng)求去查詢數(shù)據(jù)庫(kù)的時(shí)候?qū)λ右粋€(gè)互斥鎖,其余的查詢請(qǐng)求都會(huì)被阻塞住,直到鎖被釋放,從而保護(hù)數(shù)據(jù)庫(kù)。

但是也是由于它會(huì)阻塞其他線程,此時(shí)系統(tǒng)的吞吐量會(huì)下降。需要結(jié)合實(shí)際業(yè)務(wù)去考慮。

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

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