Redis之布隆過濾器BloomFilter


【引】
基數很大的集合,需要我們比較某個元素是不是存在於這個集合。如果這個查詢驗證的頻率還很高,那么如何設計呢?
【方案】
1.數據庫查詢
可能我們要考慮的就是如何去分庫了,然后再hash到對應的庫中進行查找元素。這會是一個比較復雜,實施起來也麻煩的方案。
2.HashSet
對於查詢的熱點數據,我們也可以存於Set,即內存中,這樣響應速度肯定也快,但是如何判斷哪些需要在內存哪些需要放在磁盤也是需要平衡的。
3.布隆過濾器
布隆過濾器(bloomfilter,以下簡稱bf)是用誤差率來換取空間,並且是極大的提升了空間利用率。我們可以利用bf技術,只用極小的空間(相比於set)就能夠處理這種大基數的元素查詢,雖然不能保證全部正確,但是用少量的誤差,配合DB,可以使服務器的負載控制在可以接受的范圍。
【RedBloom安裝】
簡單說,就是Redis本身是不支持bf的,得安裝插件。Linux環境中下載插件[https://github.com/RedisLabsModules/rebloom/archive/v2.2.6.tar.gz]編譯好,再在redis.conf中修改配置引用這個.so文件,重啟Redis服務即可。
參考 [https://blog.csdn.net/qq_41125219/article/details/119972808]
【簡單使用】
關鍵指令是bf.add key value , bf.madd key value1 value2 ...,bf.exists key value, bf.mexists value1 value2 ...

【基本原理】
每個布隆過濾器對應到 Redis 底層的數據結構就是一個大型的位數組和一系列的無偏哈希函數(所謂無偏就是能夠把元素的哈希值算得比較均勻):

向布隆過濾器中添加鍵值對時,會使用這一系列哈希函數分別對鍵名進行哈希運算,然后將得到的整數索引值與位數組長度進行取模運算得到最終索引位置,再把位數組的這幾個索引位都置為 1,這就完成了 bf.add 操作。
向布隆過濾器查詢指定鍵名是否存在時,和 bf.add 一樣,也會把哈希后的索引位置都算出來,看看位數組中這幾個索引位的值是否都為 1,只要有一個位為 0,則說明布隆過濾器中這個鍵名不存在。如果都為 1,也並不能說明這個鍵名就一定存在,只是很有可能存在,因為這些位被置為 1 可能是其它鍵名哈希運算時出現哈希沖突所致(概率很低,但是存在)。
如果這個位數組比較稀疏,判斷正確的概率就會很大,如果這個位數組比較稠密,判斷正確的概率就會降低,因為出現哈希沖突的概率會提高,但是相對整體而言依然是很小的比例。
【空間與誤差率】
Redis還提供了自定義參數的bf.實際使用時,如果需要的話,可以通過在 bf.add 之前執行 bf.reserve 指令自定義布隆過濾器的參數,這個指令支持三個參數:

key:指定鍵名;
error_rate:錯誤率,默認是 0.01,即 1%,你可以將其調小,但是錯誤率越低,所需要的集合容量就越大,占用的存儲空間就越大;
initial_size:初始化的集合容量(集合中存放的元素數量),默認是 100,該值越大,錯誤率越低,但所需的存儲空間也就越大,反之該值越小,所需的存儲空間越小,但錯誤率越高。

注意:如果key已經存在(Redis默認使用的bf中error_rate為0.01,initial_size為100),使用bf.reserve時會報錯的:

所以,在知道了集合總量多的情況下,當我們指定錯誤率時,我們是能夠估計它的空間占用多大的。
  k=0.7*(L/N) #N表示集合總量,L表示位數組的長度,即bit長度,過濾器的空間大小。而k表示hash函數的數量
  f=0.6185^(L/N) #f表示錯誤率,L表示位長度即空間大小,N為集合總量
【使用場景】
1. 解決緩存穿透
(1). 含義
 業務請求中數據緩存中沒有,DB中也沒有,導致類似請求直接跨過緩存,反復在DB中查詢,與此同時緩存也不會得到更新。(詳見:https://www.cnblogs.com/yaopengfei/p/13878124.html)
(2). 解決思路
 事先把存在的key都放到redis的Bloom Filter 中,他的用途就是存在性檢測,如果 BloomFilter 中不存在,那么數據一定不存在;如果 BloomFilter 中存在,實際數據也有可能會不存在。
剖析:布隆過濾器可能會誤判,放過部分請求,當不影響整體,所以目前該方案是處理此類問題最佳方案。

2. 黑名單校驗
 識別垃圾郵件,只要發送者在黑名單中的,就識別為垃圾郵件。假設黑名單的數量是數以億計的,存放起來就是非常耗費存儲空間的,布隆過濾器則是一個較好的解決方案。把所有黑名單都放在布隆過濾器中,再收到郵件時,判斷郵件地址是否在布隆過濾器中即可。
ps:
  如果用哈希表,每存儲一億個 email地址,就需要 1.6GB的內存(用哈希表實現的具體辦法是將每一個 email地址對應成一個八字節的信息指紋,然后將這些信息指紋存入哈希表,由於哈希表的存儲效率一般只有 50%,因此一個 email地址需要占用十六個字節。一億個地址大約要 1.6GB,即十六億字節的內存)。因此存貯幾十億個郵件地址可能需要上百 GB的內存。而Bloom Filter只需要哈希表 1/8到 1/4 的大小就能解決同樣的問題。

3. Web攔截器
(1). 含義
 如果相同請求則攔截,防止重復被攻擊。
(2). 解決思路
 用戶第一次請求,將請求參數放入布隆過濾器中,當第二次請求時,先判斷請求參數是否被布隆過濾器命中,從而提高緩存命中率。

【參考】
《Redis深度歷險 核心原理與應用實踐》
https://blog.csdn.net/qq_41125219/article/details/119972808
https://www.cnblogs.com/yaopengfei/p/13928512.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM