詳解Redis緩存穿透/擊穿/雪崩原理及其解決方案
1. 簡(jiǎn)介
如圖所示,一個(gè)正常的請(qǐng)求

1.客戶端請(qǐng)求張鐵牛的博客。
2.服務(wù)首先會(huì)請(qǐng)求redis,查看請(qǐng)求的內(nèi)容是否存在。
3.redis將請(qǐng)求結(jié)果返回給服務(wù),如果返回的結(jié)果有數(shù)據(jù)則執(zhí)行7;如果沒(méi)有數(shù)據(jù)則會(huì)繼續(xù)往下執(zhí)行。
4.服務(wù)從數(shù)據(jù)庫(kù)中查詢請(qǐng)求的數(shù)據(jù)。
5.數(shù)據(jù)庫(kù)將查詢的結(jié)果返回給服務(wù)。
6.如果數(shù)據(jù)庫(kù)有返回?cái)?shù)據(jù),則將返回的結(jié)果添加到redis。
7.將請(qǐng)求到的數(shù)據(jù)返回給客戶端。
2. 緩存穿透

2.1描述
通過(guò)接口訪問(wèn)一個(gè)緩存和數(shù)據(jù)庫(kù)都不存在的數(shù)據(jù)。
因?yàn)榉?wù)出于容錯(cuò)考慮,當(dāng)請(qǐng)求從持久層查不到數(shù)據(jù)則不寫(xiě)入緩存,這將導(dǎo)致請(qǐng)求這個(gè)不存在的數(shù)據(jù)每次都要到持久層去查詢,失去了緩存的意義。
此時(shí),緩存起不到保護(hù)后端持久層的意義,就像被穿透了一樣。導(dǎo)致數(shù)據(jù)庫(kù)存在被打掛的風(fēng)險(xiǎn)。
2.2 解決方案
1.接口請(qǐng)求參數(shù)的校驗(yàn)。對(duì)請(qǐng)求的接口進(jìn)行鑒權(quán),數(shù)據(jù)合法性的校驗(yàn)等;比如查詢的userId不能是負(fù)值或者包含非法字符等。
2.當(dāng)數(shù)據(jù)庫(kù)返回空值時(shí),將空值緩存到redis,并設(shè)置合理的過(guò)期時(shí)間。
3.布隆過(guò)濾器。使用布隆過(guò)濾器存儲(chǔ)所有可能訪問(wèn)的 key,不存在的 key 直接被過(guò)濾,存在的 key 則再進(jìn)一步查詢緩存和數(shù)據(jù)庫(kù)。
3. 緩存擊穿

3.1 描述
某個(gè)熱點(diǎn) key,在緩存過(guò)期的一瞬間,同時(shí)有大量的請(qǐng)求打進(jìn)來(lái),由于此時(shí)緩存過(guò)期了,所以請(qǐng)求最終都會(huì)走到數(shù)據(jù)庫(kù),造成瞬時(shí)數(shù)據(jù)庫(kù)請(qǐng)求量大、壓力驟增,導(dǎo)致數(shù)據(jù)庫(kù)存在被打掛的風(fēng)險(xiǎn)。
3.2 解決方案
1.加互斥鎖。當(dāng)熱點(diǎn)key過(guò)期后,大量的請(qǐng)求涌入時(shí),只有第一個(gè)請(qǐng)求能獲取鎖并阻塞,此時(shí)該請(qǐng)求查詢數(shù)據(jù)庫(kù),并將查詢結(jié)果寫(xiě)入redis后釋放鎖。后續(xù)的請(qǐng)求直接走緩存。
2.設(shè)置緩存不過(guò)期或者后臺(tái)有線程一直給熱點(diǎn)數(shù)據(jù)續(xù)期。
4. 緩存雪崩

4.1 描述
大量的熱點(diǎn)數(shù)據(jù)過(guò)期時(shí)間相同,導(dǎo)致數(shù)據(jù)在同一時(shí)刻集體失效。造成瞬時(shí)數(shù)據(jù)庫(kù)請(qǐng)求量大、壓力驟增,引起雪崩,導(dǎo)致數(shù)據(jù)庫(kù)存在被打掛的風(fēng)險(xiǎn)。
4.1 解決方案
1.將熱點(diǎn)數(shù)據(jù)的過(guò)期時(shí)間打散。給熱點(diǎn)數(shù)據(jù)設(shè)置過(guò)期時(shí)間時(shí)加個(gè)隨機(jī)值。
2.加互斥鎖。當(dāng)熱點(diǎn)key過(guò)期后,大量的請(qǐng)求涌入時(shí),只有第一個(gè)請(qǐng)求能獲取鎖并阻塞,此時(shí)該請(qǐng)求查詢數(shù)據(jù)庫(kù),并將查詢結(jié)果寫(xiě)入redis后釋放鎖。后續(xù)的請(qǐng)求直接走緩存。
3.設(shè)置緩存不過(guò)期或者后臺(tái)有線程一直給熱點(diǎn)數(shù)據(jù)續(xù)期。
5. 布隆過(guò)濾器
5.1 描述
布隆過(guò)濾器是防止緩存穿透的方案之一。布隆過(guò)濾器主要是解決大規(guī)模數(shù)據(jù)下不需要精確過(guò)濾的業(yè)務(wù)場(chǎng)景,如檢查垃圾郵件地址,爬蟲(chóng)URL地址去重, 解決緩存穿透問(wèn)題等。
布隆過(guò)濾器:在一個(gè)存在一定數(shù)量的集合中過(guò)濾一個(gè)對(duì)應(yīng)的元素,判斷該元素是否一定不在集合中或者可能在集合中。它的優(yōu)點(diǎn)是空間效率和查詢時(shí)間都比一般的算法要好的多,缺點(diǎn)是有一定的誤識(shí)別率和刪除困難。
5.2 數(shù)據(jù)結(jié)構(gòu)
布隆過(guò)濾器是基于bitmap和若干個(gè)hash算法實(shí)現(xiàn)的。如下圖所示:

1.元素tie經(jīng)過(guò)hash1,hash2,hash3運(yùn)算出對(duì)應(yīng)的三個(gè)值落到了數(shù)組下標(biāo)為4,6,8的位置上,并將其位置的默認(rèn)值0,修改成1。
2.元素niu同理落到了數(shù)組下標(biāo)為1,3,4的位置上,并將其位置的默認(rèn)值0,修改成1。
此時(shí)bitmap中已經(jīng)存儲(chǔ)了tie,niu數(shù)據(jù)元素。
當(dāng)請(qǐng)求想通過(guò)布隆過(guò)濾器判斷tie元素在程序中是否存在時(shí),通過(guò)hash運(yùn)算結(jié)果到數(shù)組對(duì)應(yīng)下標(biāo)位置上發(fā)現(xiàn)值已經(jīng)都被置為1,此時(shí)返回true。
5.3 “一定不在集合中”

如圖所示:
元素zhang通過(guò)布隆過(guò)濾器判斷時(shí),下標(biāo)0,2都為0,則直接返回false。
也就是當(dāng)判斷不在bitmap中的元素時(shí),經(jīng)過(guò)hash運(yùn)算得到的結(jié)果在bitmap中只要有一個(gè)為0,則該數(shù)據(jù)一定不存在。
5.4 “可能在集合中”

如圖所示:
元素shuaibi通過(guò)布隆過(guò)濾器判斷時(shí),hash運(yùn)算的結(jié)果落到了下標(biāo)1,3,8上,此時(shí)對(duì)應(yīng)下標(biāo)位置的值都為1,則直接返回true。
這下就尷尬了,因?yàn)閷?shí)際程序中并沒(méi)有數(shù)據(jù)shuaibi,但布隆過(guò)濾器返回的結(jié)果顯示有這個(gè)元素。這就是布隆過(guò)濾器的缺點(diǎn),存在誤判情況。
5.5 ”刪除困難“
為什么布隆過(guò)濾器刪除困難呢,如圖所示:

如果刪除了“tie”元素,4號(hào)位被置為0,則會(huì)影響niu元素的判斷,因?yàn)?code>4號(hào)位為0,進(jìn)行數(shù)據(jù)校驗(yàn)時(shí)返回0,則會(huì)認(rèn)為程序中沒(méi)有niu元素。
那小伙伴會(huì)問(wèn),4號(hào)位不置為0,行不行?
如果刪除了元素,hash碰撞的數(shù)組下標(biāo)不置為0,那么如果繼續(xù)驗(yàn)證該元素的話,布隆過(guò)濾器會(huì)繼續(xù)返回true,但實(shí)際上元素已經(jīng)刪除了。
所以布隆過(guò)濾器數(shù)據(jù)刪除困難,如果要?jiǎng)h除的話,可以參考Counting Bloom Filter。
5.6 為什么不使用HashMap呢?
如果用HashSet或Hashmap存儲(chǔ)的話,每一個(gè)用戶ID都要存成int,占4個(gè)字節(jié)即32bit。而一個(gè)用戶在bitmap中只需要1個(gè)bit,內(nèi)存節(jié)省了32倍。
并且大數(shù)據(jù)量會(huì)產(chǎn)生大量的hash沖突,結(jié)果就是產(chǎn)生hash沖突的數(shù)據(jù),仍然會(huì)進(jìn)行遍歷挨個(gè)比對(duì)(即使轉(zhuǎn)成紅黑樹(shù)),這樣對(duì)內(nèi)存空間和查詢效率的提升,仍然是有限的。
當(dāng)然:數(shù)據(jù)量不大時(shí),盡管使用。而且hashmap方便進(jìn)行CRUD😂
到此這篇關(guān)于詳解緩存穿透/擊穿/雪崩原理及其解決方案的文章就介紹到這了,更多相關(guān)緩存穿透/擊穿/雪崩內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用Redis實(shí)現(xiàn)防止接口重復(fù)提交功能
大家好,本篇文章主要講的是利用Redis實(shí)現(xiàn)防止接口重復(fù)提交功能,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12
解析高可用Redis服務(wù)架構(gòu)分析與搭建方案
我們按照由簡(jiǎn)至繁的步驟,搭建一個(gè)最小型的高可用的Redis服務(wù)。 本文通過(guò)四種方案給大家介紹包含每種方案的優(yōu)缺點(diǎn)及詳細(xì)解說(shuō),具體內(nèi)容詳情跟隨小編一起看看吧2021-06-06
Redis報(bào)錯(cuò):Could not create server TCP 
這篇文章主要介紹了Redis報(bào)錯(cuò):Could not create server TCP listening socket 127.0.0.1:6379: bind:解決方法,是安裝與啟動(dòng)Redis過(guò)程中比較常見(jiàn)的問(wèn)題,需要的朋友可以參考下2023-06-06
Redis解決緩存雪崩、穿透和擊穿的問(wèn)題(Redis使用必看)
這篇文章主要給大家介紹了Redis解決緩存雪崩、緩存穿透、緩存擊穿的解決方案,文中有詳細(xì)的圖文介紹,具有一定的參考價(jià)值,需要的朋友可以參考下2023-08-08
Redisson?框架中的分布式鎖實(shí)現(xiàn)方法
這篇文章主要介紹了Redisson?框架中的分布式鎖,實(shí)現(xiàn)分布式鎖通常有三種方式:數(shù)據(jù)庫(kù)、Redis 和 Zookeeper,我們比較常用的是通過(guò) Redis 和 Zookeeper 實(shí)現(xiàn)分布式鎖,需要的朋友可以參考下2024-03-03
全網(wǎng)最完整的Redis新手入門(mén)指導(dǎo)教程
這篇文章主要給大家介紹了Redis新手入門(mén)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Redis實(shí)現(xiàn)分布式事務(wù)的示例
Redis雖不支持傳統(tǒng)SQL數(shù)據(jù)庫(kù)ACID特性的事務(wù),但提供了事務(wù)特性,允許多命令捆綁執(zhí)行,通過(guò)命令MULTI、EXEC、DISCARD、WATCH實(shí)現(xiàn),感興趣的可以了解一下2024-10-10
Redis實(shí)戰(zhàn)之百度首頁(yè)新聞熱榜的實(shí)現(xiàn)代碼
這篇文章主要介紹了Redis實(shí)戰(zhàn)之百度首頁(yè)新聞熱榜的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
Redis中的數(shù)據(jù)結(jié)構(gòu)跳表詳解
跳表是一種基于并聯(lián)的鏈表結(jié)構(gòu),用于在有序元素序列中快速查找元素的數(shù)據(jù)結(jié)構(gòu),本文給大家介紹Redis中的數(shù)據(jù)結(jié)構(gòu)跳表,感興趣的朋友跟隨小編一起看看吧2024-06-06

