Redis處理高并發(fā)之布隆過濾器詳解
前言
隨著我們業(yè)務(wù)開發(fā)越來越來大,并染請求就會越來越多,那么我們的項(xiàng)目的壓力就會越來越大,基本都會使用緩存,除本地緩存,還會用到redis緩存,但是你以為使用緩存就沒啥問題了么,那肯定不是的,使用了緩存又會出現(xiàn)新的問題,比如,緩存的key失效導(dǎo)致大量的請求到數(shù)據(jù)庫,大量的讀請求瞬間到達(dá)了數(shù)據(jù)庫,cpu的使用率爆增,導(dǎo)致數(shù)據(jù)庫都可能掛掉,這種情況下我們就要考慮使用redis的布隆過濾器了。
緩存穿透、擊穿、雪崩
首先我們從緩存會出現(xiàn)的幾種問題,來進(jìn)行分析,在高并發(fā)的場景下如果出現(xiàn)這種情況,我們應(yīng)該如何解決。
正常情況下,我們的web應(yīng)用會先去請求緩存服務(wù),如果緩存命中,那么就去拿緩存里面的數(shù)據(jù),返回結(jié)果給應(yīng)用,
緩存穿透
緩存穿透與緩存雪崩和緩存擊穿還是不一樣的,雪崩和擊穿的情況下,數(shù)據(jù)庫的數(shù)據(jù)都是真正常的,可以去請求數(shù)據(jù)庫獲取數(shù)據(jù),只是緩存層出現(xiàn)問題,等待緩存恢復(fù)了,就會減輕數(shù)據(jù)庫的壓力。 而緩存透不一樣的就是,緩存和數(shù)據(jù)庫都沒有要請求的數(shù)據(jù),大量的請求來了,數(shù)據(jù)庫的壓力很大。
出現(xiàn)情況
- 數(shù)據(jù)庫數(shù)據(jù)被大量清除,導(dǎo)致訪問不到
- 黑客惡意攻擊
常見的解決方案
- redis緩存空值,請求不到的時候返回給應(yīng)用空值。
- 使用布隆過濾器,把數(shù)據(jù)庫的一部分?jǐn)?shù)據(jù)hash到布隆過濾器里,在請求數(shù)據(jù)庫之前先去布隆過濾器里篩選到一部分請求,判斷數(shù)據(jù)是否存在,避免直接去訪問數(shù)據(jù)庫。
緩存擊穿
出現(xiàn)情況
- 大量熱點(diǎn)數(shù)據(jù)庫過期,導(dǎo)致無法從緩存獲取到數(shù)據(jù),大量請求數(shù)據(jù)庫也無法返回書就
解決方案
- 加鎖,保證同一時間內(nèi),只允許有一個線程去更新緩存,等鎖釋放后在重新去請求緩存。
- 熱點(diǎn)數(shù)據(jù)不去設(shè)置過期時間,如果要設(shè)置過期時間,在過期的時候通知后臺去更新緩存的過期時間。
緩存雪崩
- 大量緩存在同一時間失效,導(dǎo)致大量請求進(jìn)入數(shù)據(jù)庫
- redis故障宕機(jī),導(dǎo)致緩存不能使用。
解決方案
- 同上加鎖
- 給緩存的過期時間加入隨機(jī)數(shù),保證緩存不會在同一時間同時失效。
- 副本key策略,就是對于一個key,在它的基礎(chǔ)上在設(shè)置一個key,它們的value都是一樣的,只不過一個設(shè)置過期時間、一個不設(shè)置過期時間,相當(dāng)于給key做了個副本,只不過在更新緩存的時候,副本key也是要更新的,避免出現(xiàn)數(shù)據(jù)不一致的現(xiàn)象。
布隆過濾器 Bloom filter
前面提到過布隆過濾器在請求比較高的時候,可以幫助我們抵擋一部分請求,從而減輕數(shù)據(jù)庫的壓力,布隆過濾器的數(shù)據(jù)結(jié)構(gòu)是一個二進(jìn)制的bit向量,或者說是一個bit數(shù)組,它相對于list、set、map這些集合,它占用的空間更少,不足之處處就是返回的結(jié)果會有一定概率的誤差。
public static void main(String[] args) { int size = 1_000_000; BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size); for (int i = 0; i < size; i++) { bloomFilter.put(i); } for (int i = 0; i < size; i++) { if (!bloomFilter.mightContain(i)) { System.out.println("有漏網(wǎng)之魚"); } } List<Integer> list = new ArrayList<>(1000); for (int i = size + 10000; i < size + 20000; i++) { if (bloomFilter.mightContain(i)) { list.add(i); } } System.out.println("有誤差的數(shù)量:" + list.size()); }
確實(shí)有誤差的數(shù)量,但是誤差量不大,追求效率的同時只是犧牲一點(diǎn)誤差了。
總結(jié)
加鎖的排隊(duì)的場景確實(shí)能幫助我們很好的解決緩存穿透、擊穿的一些問題,但是效率也是非常低了,因?yàn)槊總€請求都是排隊(duì)等待,如果可以接受輕微誤差的話,布隆過濾器的確是個很不錯的選擇,Bloom filter的bitmap的存儲效率確實(shí)很高。
以上就是Redis處理高并發(fā)之布隆過濾器詳解的詳細(xì)內(nèi)容,更多關(guān)于Redis布隆過濾器處理高并發(fā)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Redis GEO實(shí)現(xiàn)搜索附近用戶的項(xiàng)目實(shí)踐
RedisGEO主要用于存儲地理位置信息,并對存儲的信息進(jìn)行操作,本文主要介紹了Redis GEO實(shí)現(xiàn)搜索附近用戶的項(xiàng)目實(shí)踐,具有一定的參考價值,感興趣的可以了解一下2024-05-05Redis高級數(shù)據(jù)類型Hyperloglog、Bitmap的使用
很多小伙伴在面試中都會被問道 Redis的常用數(shù)據(jù)結(jié)構(gòu)有哪些?可能很大一部分回答都是 string、hash、list、set、zset,但其實(shí)還有Hyperloglog和Bitmap,本文就來介紹一下2021-05-05Redis 的查詢很快的原因解析及Redis 如何保證查詢的高效
由于redis是內(nèi)存數(shù)據(jù)庫,歸功于它的數(shù)據(jù)結(jié)構(gòu)所以查詢效率非常高,今天通過本文給大家介紹下Redis 的查詢很快的原因解析及Redis 如何保證查詢的高效,感興趣的朋友一起看看吧2022-03-03