緩存失效###
原因:引起這個(gè)原因的主要因素是高并發(fā)下,我們一般設(shè)定一個(gè)緩存的過(guò)期時(shí)間時(shí),可能有一些會(huì)設(shè)置5分鐘啊,10分鐘這些;并發(fā)很高時(shí)可能會(huì)出在某一個(gè)時(shí)間同時(shí)生成了很多的緩存,并且過(guò)期時(shí)間在同一時(shí)刻,這個(gè)時(shí)候就可能引發(fā)——當(dāng)過(guò)期時(shí)間到后,這些緩存將同時(shí)失效。
影響:緩存同時(shí)失效時(shí)產(chǎn)生的雪崩效應(yīng),將所有請(qǐng)求全部放在數(shù)據(jù)庫(kù)上,這樣很容易就達(dá)到數(shù)據(jù)庫(kù)的瓶頸,導(dǎo)致服務(wù)無(wú)法正常提供。盡量避免這種場(chǎng)景的發(fā)生。
解決:一個(gè)簡(jiǎn)單方案就是將緩存失效時(shí)間分散開,不要所以緩存時(shí)間長(zhǎng)度都設(shè)置成5分鐘或者10分鐘;比如我們可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值,比如1-5分鐘隨機(jī),這樣每一個(gè)緩存的過(guò)期時(shí)間的重復(fù)率就會(huì)降低,就很難引發(fā)集體失效的事件。
緩存穿透###
場(chǎng)景:指查詢一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)被動(dòng)寫的,并且出于容錯(cuò)考慮,如果從存儲(chǔ)層查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到存儲(chǔ)層去查詢,失去了緩存的意義。
影響:當(dāng)在流量較大時(shí),出現(xiàn)這樣的情況,一直請(qǐng)求DB,很容易導(dǎo)致服務(wù)掛掉。
解決:
在封裝的緩存SET和GET部分增加個(gè)步驟,如果查詢一個(gè)KEY不存在,就已這個(gè)KEY為前綴設(shè)定一個(gè)標(biāo)識(shí)KEY;以后再查詢?cè)揔EY的時(shí)候,先查詢標(biāo)識(shí)KEY,如果標(biāo)識(shí)KEY存在,就返回一個(gè)協(xié)定好的非false或者NULL值,然后APP做相應(yīng)的處理,這樣緩存層就不會(huì)被穿透。當(dāng)然這個(gè)驗(yàn)證KEY的失效時(shí)間不能太長(zhǎng)。
如果一個(gè)查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在,還是系統(tǒng)故障),我們?nèi)匀话堰@個(gè)空結(jié)果進(jìn)行緩存,但它的過(guò)期時(shí)間會(huì)很短,一般只有幾分鐘。
采用布隆過(guò)濾器,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè)bitmap攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力。
緩存并發(fā)###
場(chǎng)景:當(dāng)網(wǎng)站并發(fā)訪問(wèn)高,一個(gè)緩存如果失效,可能出現(xiàn)多個(gè)進(jìn)程同時(shí)查詢DB,同時(shí)設(shè)置緩存的情況,如果并發(fā)確實(shí)很大,這也可能造成DB壓力過(guò)大,還有緩存頻繁更新的問(wèn)題。
解決:對(duì)緩存查詢加鎖,如果KEY不存在,就加鎖,然后查DB入緩存,然后解鎖;其他進(jìn)程如果發(fā)現(xiàn)有鎖就等待,然后等解鎖后返回?cái)?shù)據(jù)或者進(jìn)入DB查詢。