原來(lái)大廠(chǎng)都這么解決Redis緩存雪崩、緩存穿透、緩存擊穿
1 緩存雪崩
1.1 什么是緩存雪崩?
由于
設(shè)置緩存時(shí),key都采用了相同expire
更新策略
數(shù)據(jù)熱點(diǎn)
緩存服務(wù)宕機(jī)
等原因,可能導(dǎo)致緩存數(shù)據(jù)同一時(shí)刻大規(guī)模不可用,或者都更新。
1.2 解決方案
更新策略在時(shí)間上做到比較均勻
使用的熱數(shù)據(jù)盡量分散到不同的機(jī)器上
多臺(tái)機(jī)器做主從復(fù)制或者多副本,實(shí)現(xiàn)高可用
實(shí)現(xiàn)熔斷限流機(jī)制,對(duì)系統(tǒng)進(jìn)行負(fù)載能力控制
在原有失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值,比如1~5分鐘的隨機(jī),這樣每個(gè)緩存的過(guò)期時(shí)間重復(fù)率就會(huì)降低,集體失效概率也會(huì)大大降低。
2 緩存穿透
2.1 什么是緩存穿透?
大量并發(fā)查詢(xún)不存在的KEY,導(dǎo)致都直接將壓力透?jìng)鞯綌?shù)據(jù)庫(kù)。
為什么會(huì)多次透?jìng)髂兀坎淮嬖谝恢睘榭铡?需要注意讓緩存能夠區(qū)分KEY不存在和查詢(xún)到一個(gè)空值。
例如:訪(fǎng)問(wèn)id=-1的數(shù)據(jù)??赡艹霈F(xiàn)繞過(guò)Redis依然頻繁訪(fǎng)問(wèn)數(shù)據(jù)庫(kù),稱(chēng)為緩存穿透,多出現(xiàn)在查詢(xún)?yōu)閚ull的情況不被緩存時(shí)。
2.2 解決方案
緩存空值的KEY,這樣第一次不存在也會(huì)被加載會(huì)記錄,下次拿到有這個(gè)KEY
Bloom過(guò)濾或RoaringBitmap 判斷KEY是否存在
最常見(jiàn)的布隆過(guò)濾器,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè)bitmap攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢(xún)壓力。
完全以緩存為準(zhǔn),使用 延遲異步加載 的策略2,這樣就不會(huì)觸發(fā)更新。
更為簡(jiǎn)單粗暴的方法,如果一個(gè)查詢(xún)返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在,還是系統(tǒng)故障),仍然把這個(gè)空結(jié)果進(jìn)行緩存,但它的過(guò)期時(shí)間會(huì)很短,最長(zhǎng)不超過(guò)5min。

3 緩存擊穿
擊穿是針對(duì)某一key緩存,而雪崩是很多key。
某KEY失效時(shí),正好有大量并發(fā)請(qǐng)求訪(fǎng)問(wèn)該KEY。
通常使用緩存 + 過(guò)期時(shí)間的策略來(lái)幫助我們加速接口的訪(fǎng)問(wèn)速度,減少了后端負(fù)載,同時(shí)保證功能的更新,一般情況下這種模式已經(jīng)基本滿(mǎn)足要求了。
但如下問(wèn)題若同時(shí)出現(xiàn),可能對(duì)系統(tǒng)致命:
為熱點(diǎn)key,訪(fǎng)問(wèn)量非常大
緩存的構(gòu)建是需要時(shí)間(可能是個(gè)復(fù)雜過(guò)程,例如復(fù)雜SQL、多次I/O、多個(gè)接口依賴(lài))
于是就會(huì)導(dǎo)致: 在緩存失效瞬間,有大量線(xiàn)程構(gòu)建緩存,導(dǎo)致后端負(fù)載加劇,甚至可能讓系統(tǒng)崩潰。

3.2 解決方案
所以問(wèn)題就在于限制處理線(xiàn)程的數(shù)量,即KEY的更新操作添加全局互斥鎖。
互斥鎖
在緩存失效時(shí)(判斷拿出來(lái)的值為空),不是立即去load db,而是
先使用緩存工具的某些帶成功操作返回值的操作(Redis的SETNX)去set一個(gè)mutex key
當(dāng)操作返回成功時(shí),再load db的操作并回設(shè)緩存;否則,就重試整個(gè)get緩存的方法。

提前"使用互斥鎖(mutex key):
在value內(nèi)部設(shè)置1個(gè)超時(shí)值(timeout1), timeout1比實(shí)際的memcache timeout(timeout2)小。當(dāng)從cache讀取到timeout1發(fā)現(xiàn)它已經(jīng)過(guò)期時(shí)候,馬上延長(zhǎng)timeout1并重新設(shè)置到cache。然后再?gòu)臄?shù)據(jù)庫(kù)加載數(shù)據(jù)并設(shè)置到cache中。偽代碼如下:

緩存為準(zhǔn)
使用異步線(xiàn)程負(fù)責(zé)維護(hù)緩存的數(shù)據(jù),定期或根據(jù)條件觸發(fā)更新,這樣就不會(huì)觸發(fā)更新。
這些年做Java開(kāi)發(fā)我整理了一份完整的java的系統(tǒng)化資料,從Javase- ssm-springcloud,包括了面試題,PDF電子書(shū),網(wǎng)上商城項(xiàng)目,個(gè)人博客項(xiàng)目,分布式項(xiàng)目等都有想學(xué)習(xí)Java或者轉(zhuǎn)行,大學(xué)生都非常實(shí)用,無(wú)任何套路免費(fèi)提供,,加我裙下載,有什么問(wèn)題都可以加入我的QQ裙:735721532,自行獲取~