目錄
- 1. 簡介
- 2. 緩存穿透
- 3. 緩存擊穿
- 4. 緩存雪崩
- 5. 布隆過濾器
- 5.1 描述
- 5.2 數據結構
- 5.3 “一定不在集合中”
- 5.4 “可能在集合中”
- 5.5 ”刪除困難“
- 5.6 為什么不使用HashMap呢?
1. 簡介
如圖所示,一個正常的請求
1.客戶端請求張鐵牛的博客。
2.服務首先會請求redis,查看請求的內容是否存在。
3.redis將請求結果返回給服務,如果返回的結果有數據則執(zhí)行7
;如果沒有數據則會繼續(xù)往下執(zhí)行。
4.服務從數據庫中查詢請求的數據。
5.數據庫將查詢的結果返回給服務。
6.如果數據庫有返回數據,則將返回的結果添加到redis。
7.將請求到的數據返回給客戶端。
2. 緩存穿透
2.1描述
通過接口訪問一個緩存和數據庫都不存在的數據。
因為服務出于容錯考慮,當請求從持久層查不到數據則不寫入緩存,這將導致請求這個不存在的數據每次都要到持久層去查詢,失去了緩存的意義。
此時,緩存起不到保護后端持久層的意義,就像被穿透了一樣。導致數據庫存在被打掛的風險。
2.2 解決方案
1.接口請求參數的校驗。對請求的接口進行鑒權,數據合法性的校驗等;比如查詢的userId不能是負值或者包含非法字符等。
2.當數據庫返回空值時,將空值緩存到redis,并設置合理的過期時間。
3.布隆過濾器。使用布隆過濾器存儲所有可能訪問的 key,不存在的 key 直接被過濾,存在的 key 則再進一步查詢緩存和數據庫。
3. 緩存擊穿
3.1 描述
某個熱點 key,在緩存過期的一瞬間,同時有大量的請求打進來,由于此時緩存過期了,所以請求最終都會走到數據庫,造成瞬時數據庫請求量大、壓力驟增,導致數據庫存在被打掛的風險。
3.2 解決方案
1.加互斥鎖。當熱點key過期后,大量的請求涌入時,只有第一個請求能獲取鎖并阻塞,此時該請求查詢數據庫,并將查詢結果寫入redis后釋放鎖。后續(xù)的請求直接走緩存。
2.設置緩存不過期或者后臺有線程一直給熱點數據續(xù)期。
4. 緩存雪崩
4.1 描述
大量的熱點數據過期時間相同,導致數據在同一時刻集體失效。造成瞬時數據庫請求量大、壓力驟增,引起雪崩,導致數據庫存在被打掛的風險。
4.1 解決方案
1.將熱點數據的過期時間打散。給熱點數據設置過期時間時加個隨機值。
2.加互斥鎖。當熱點key過期后,大量的請求涌入時,只有第一個請求能獲取鎖并阻塞,此時該請求查詢數據庫,并將查詢結果寫入redis后釋放鎖。后續(xù)的請求直接走緩存。
3.設置緩存不過期或者后臺有線程一直給熱點數據續(xù)期。
5. 布隆過濾器
5.1 描述
布隆過濾器是防止緩存穿透的方案之一。布隆過濾器主要是解決大規(guī)模數據下不需要精確過濾的業(yè)務場景,如檢查垃圾郵件地址,爬蟲URL地址去重, 解決緩存穿透問題等。
布隆過濾器:在一個存在一定數量的集合中過濾一個對應的元素,判斷該元素是否一定不在集合中或者可能在集合中。它的優(yōu)點是空間效率和查詢時間都比一般的算法要好的多,缺點是有一定的誤識別率和刪除困難。
5.2 數據結構
布隆過濾器是基于bitmap
和若干個hash算法
實現的。如下圖所示:
1.元素tie
經過hash1,hash2,hash3
運算出對應的三個值落到了數組下標為4,6,8
的位置上,并將其位置的默認值0
,修改成1
。
2.元素niu
同理落到了數組下標為1,3,4
的位置上,并將其位置的默認值0
,修改成1
。
此時bitmap
中已經存儲了tie
,niu
數據元素。
當請求想通過布隆過濾器判斷tie
元素在程序中是否存在時,通過hash
運算結果到數組對應下標位置上發(fā)現值已經都被置為1
,此時返回true
。
5.3 “一定不在集合中”
如圖所示:
元素zhang
通過布隆過濾器判斷時,下標0,2
都為0
,則直接返回false
。
也就是當判斷不在bitmap
中的元素時,經過hash運算
得到的結果在bitmap
中只要有一個為0
,則該數據一定不存在。
5.4 “可能在集合中”
如圖所示:
元素shuaibi
通過布隆過濾器判斷時,hash運算
的結果落到了下標1,3,8
上,此時對應下標位置的值都為1
,則直接返回true
。
這下就尷尬了,因為實際程序中并沒有數據shuaibi
,但布隆過濾器返回的結果顯示有這個元素。這就是布隆過濾器的缺點,存在誤判情況。
5.5 ”刪除困難“
為什么布隆過濾器刪除困難呢,如圖所示:
如果刪除了“tie”元素,4
號位被置為0
,則會影響niu
元素的判斷,因為4
號位為0
,進行數據校驗時返回0
,則會認為程序中沒有niu
元素。
那小伙伴會問,4號位不置為0,行不行?
如果刪除了元素,hash碰撞的數組下標不置為0,那么如果繼續(xù)驗證該元素的話,布隆過濾器會繼續(xù)返回true,但實際上元素已經刪除了。
所以布隆過濾器數據刪除困難,如果要刪除的話,可以參考Counting Bloom Filter
。
5.6 為什么不使用HashMap呢?
如果用HashSet或Hashmap存儲的話,每一個用戶ID都要存成int,占4個字節(jié)即32bit。而一個用戶在bitmap中只需要1個bit,內存節(jié)省了32倍。
并且大數據量會產生大量的hash沖突,結果就是產生hash沖突的數據,仍然會進行遍歷挨個比對(即使轉成紅黑樹),這樣對內存空間和查詢效率的提升,仍然是有限的。
當然:數據量不大時,盡管使用。而且hashmap方便進行CRUD😂
到此這篇關于詳解緩存穿透/擊穿/雪崩原理及其解決方案的文章就介紹到這了,更多相關緩存穿透/擊穿/雪崩內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- java若依框架集成redis緩存詳解
- Redis使用元素刪除的布隆過濾器來解決緩存穿透問題
- 關于redisson緩存序列化的幾枚大坑說明
- springboot使用Redis作緩存使用入門教程
- 淺談Redis 緩存的三大問題及其解決方案
- 淺談java如何實現Redis的LRU緩存機制
- 在項目中使用redis做緩存的一些思路