這篇文章主要講解了解決redis緩存及熱點(diǎn)key問題,內(nèi)容清晰明了,對(duì)此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會(huì)有幫助。
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),漳平企業(yè)網(wǎng)站建設(shè),漳平品牌網(wǎng)站建設(shè),網(wǎng)站定制,漳平網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,漳平網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
今天又學(xué)到了很多,感覺雪崩和穿透很有意思理解起來也比較清晰,然后我搜索了一些資料,給自己做一個(gè)普及
我們通常使用 緩存 + 過期時(shí)間的策略來幫助我們加速接口的訪問速度,減少了后端負(fù)載,同時(shí)保證功能的更新
緩存穿透
緩存系統(tǒng),按照KEY去查詢VALUE,當(dāng)KEY對(duì)應(yīng)的VALUE一定不存在的時(shí)候并對(duì)KEY并發(fā)請(qǐng)求量很大的時(shí)候,就會(huì)對(duì)后端造成很大的壓力。
(查詢一個(gè)必然不存在的數(shù)據(jù)。比如文章表,查詢一個(gè)不存在的id,每次都會(huì)訪問DB,如果有人惡意破壞,很可能直接對(duì)DB造成影響。)
由于緩存不命中,每次都要查詢持久層。從而失去緩存的意義。
解決方法:
1、緩存層緩存空值。
–緩存太多空值,占用更多空間。(優(yōu)化:給個(gè)空值過期時(shí)間)
–存儲(chǔ)層更新代碼了,緩存層還是空值。(優(yōu)化:后臺(tái)設(shè)置時(shí)主動(dòng)刪除空值,并緩存把值進(jìn)去)
2、將數(shù)據(jù)庫(kù)中所有的查詢條件,放到布隆過濾器中。當(dāng)一個(gè)查詢請(qǐng)求來臨的時(shí)候,先經(jīng)過布隆過濾器進(jìn)行檢查,如果請(qǐng)求存在這個(gè)條件中,那么繼續(xù)執(zhí)行,如果不在,直接丟棄。
備注:
比如數(shù)據(jù)庫(kù)中有10000個(gè)條件,那么布隆過濾器的容量size設(shè)置的要稍微比10000大一些,比如12000.
對(duì)于誤判率的設(shè)置,根據(jù)實(shí)際項(xiàng)目,以及硬件設(shè)施來具體決定。但是一定不能設(shè)置為0,并且誤判率設(shè)置的越小,哈希函數(shù)跟數(shù)組長(zhǎng)度都會(huì)更多跟更長(zhǎng),那么對(duì)硬件,內(nèi)存中間的要求就會(huì)相應(yīng)的高。
private static BloomFilter
有了size跟誤判率,那么布隆過濾器就會(huì)產(chǎn)生相應(yīng)的哈希函數(shù)跟數(shù)組。
綜上:我們可以利用布隆過濾器,將redis緩存擊穿控制在一個(gè)可容忍的范圍內(nèi)。
緩存雪崩(緩存失效)
如果緩存集中在一段時(shí)間內(nèi)失效,發(fā)生大量的緩存穿透,所有的查詢都落在數(shù)據(jù)庫(kù)上,造成了緩存雪崩。
緩存層宕掉后,流量會(huì)像奔逃的野牛一樣,打向后端存儲(chǔ)
解決方法:
熱點(diǎn)key
(1) 這個(gè)key是一個(gè)熱點(diǎn)key(例如一個(gè)重要的新聞,一個(gè)熱門的八卦新聞等等),所以這種key訪問量可能非常大。
(2) 緩存的構(gòu)建是需要一定時(shí)間的。(可能是一個(gè)復(fù)雜計(jì)算,例如復(fù)雜的sql、多次IO、多個(gè)依賴(各種接口)等等)
于是就會(huì)出現(xiàn)一個(gè)致命問題:在緩存失效的瞬間,有大量線程來構(gòu)建緩存(見下圖),造成后端負(fù)載加大,甚至可能會(huì)讓系統(tǒng)崩潰 。
解決方法:
1. 使用互斥鎖(mutex key):這種解決方案思路比較簡(jiǎn)單,就是只讓一個(gè)線程構(gòu)建緩存,其他線程等待構(gòu)建緩存的線程執(zhí)行完,重新從緩存獲取數(shù)據(jù)就可以了
2. "提前"使用互斥鎖(mutex key):在value內(nèi)部設(shè)置1個(gè)超時(shí)值(timeout1), timeout1比實(shí)際的memcache timeout(timeout2)小。當(dāng)從cache讀取到timeout1發(fā)現(xiàn)它已經(jīng)過期時(shí)候,馬上延長(zhǎng)timeout1并重新設(shè)置到cache。然后再?gòu)臄?shù)據(jù)庫(kù)加載數(shù)據(jù)并設(shè)置到cache中。
3. "永遠(yuǎn)不過期":
這里的“永遠(yuǎn)不過期”包含兩層意思:
(1) 從redis上看,確實(shí)沒有設(shè)置過期時(shí)間,這就保證了,不會(huì)出現(xiàn)熱點(diǎn)key過期問題,也就是“物理”不過期。
(2) 從功能上看,如果不過期,那不就成靜態(tài)的了嗎?所以我們把過期時(shí)間存在key對(duì)應(yīng)的value里,如果發(fā)現(xiàn)要過期了,通過一個(gè)后臺(tái)的異步線程進(jìn)行緩存的構(gòu)建,也就是“邏輯”過期
4. 資源保護(hù):可以做資源的隔離保護(hù)主線程池,如果把這個(gè)應(yīng)用到緩存的構(gòu)建也未嘗不可。
四種方案對(duì)比:
作為一個(gè)并發(fā)量較大的互聯(lián)網(wǎng)應(yīng)用,我們的目標(biāo)有3個(gè):
1. 加快用戶訪問速度,提高用戶體驗(yàn)。
2. 降低后端負(fù)載,保證系統(tǒng)平穩(wěn)。
3. 保證數(shù)據(jù)“盡可能”及時(shí)更新(要不要完全一致,取決于業(yè)務(wù),而不是技術(shù)。)
所以第二節(jié)中提到的四種方法,可以做如下比較,還是那就話:沒有最好,只有最合適。
解決方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
簡(jiǎn)單分布式鎖(Tim yang) | 1. 思路簡(jiǎn)單 2. 保證一致性 | 1. 代碼復(fù)雜度增大 2. 存在死鎖的風(fēng)險(xiǎn) 3. 存在線程池阻塞的風(fēng)險(xiǎn) |
加另外一個(gè)過期時(shí)間(Tim yang) | 1. 保證一致性 | 同上 |
不過期(本文) | 1. 異步構(gòu)建緩存,不會(huì)阻塞線程池 | 1. 不保證一致性。 2. 代碼復(fù)雜度增大(每個(gè)value都要維護(hù)一個(gè)timekey)。 3. 占用一定的內(nèi)存空間(每個(gè)value都要維護(hù)一個(gè)timekey)。 |
資源隔離組件hystrix(本文) | 1. hystrix技術(shù)成熟,有效保證后端。 2. hystrix監(jiān)控強(qiáng)大。 | 1. 部分訪問存在降級(jí)策略。 |
總結(jié)
1. 熱點(diǎn)key + 過期時(shí)間 + 復(fù)雜的構(gòu)建緩存過程 => mutex key問題
2. 構(gòu)建緩存一個(gè)線程做就可以了。
3. 四種解決方案:沒有最佳只有最合適。
看完上述內(nèi)容,是不是對(duì)解決Redis緩存及熱點(diǎn)key問題有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。