BloomFilter的常見使用場景 使用BloomFilter布隆過濾器解決緩存擊穿、垃圾郵件識別、集合判重

使用BloomFilter布隆過濾器解決緩存擊穿、垃圾郵件識別、集合判重

Bloom Filter是一個佔用空間很小、效率很高的隨機數據結構,它由一個bit數組和一組Hash算法構成。可用於判斷一個元素是否在一個集合中,查詢效率很高(1-N,最優能逼近於1)。

在很多場景下,我們都需要一個能迅速判斷一個元素是否在一個集合中。譬如:

網頁爬蟲對URL的去重,避免爬取相同的URL地址;

反垃圾郵件,從數十億個垃圾郵件列表中判斷某郵箱是否垃圾郵箱(同理,垃圾短信);

緩存擊穿,將已存在的緩存放到布隆中,當黑客訪問不存在的緩存時迅速返回避免緩存及DB掛掉。

可能有人會問,我們直接把這些數據都放到數據庫或者redis之類的緩存中不就行了,查詢時直接匹配不就OK了?

是的,當這個集合量比較小,你內存又夠大時,是可以這樣做,你可以直接弄個HashSet、HashMap就OK了。但是當這個量以數十億計,內存裝不下,數據庫檢索極慢時該怎麼辦。

以垃圾郵箱爲例

方案比較

1.將所有垃圾郵箱地址存到數據庫,匹配時遍歷
2.用HashSet存儲所有地址,匹配時接近O(1)的效率查出來
3.將地址用MD5算法或其他單向映射算法計算後存入HashSet,無論地址多大,保存的只有MD5後的固定位數
4.布隆過濾器,將所有地址經過多個Hash算法,映射到一個bit數組

優缺點

方案1和2都是保存完整的地址,佔用空間大。一個地址16字節,10億即可達到上百G的內存。HashSet效率逼近O(1),數據庫就不談效率了,不在一個數量級。
方案3保存部分信息,佔用空間小於存儲完整信息,存在衝突的可能(非垃圾郵箱可能MD5後和某垃圾郵箱一樣,概率低)
方案4將所有地址經過Hash後映射到同一個bit數組,看清了,只有一個超大的bit數組,保存所有的映射,佔用空間極小,衝突概率高。

大家知道,java中的HashMap有個擴容參數默認是0.75,也就是你想存75個數,至少需要一個100的數組,而且還會有不少的衝突。實際上,Hash的存儲效率是0.5左右,存5個數需要10個的空間。算起來佔用空間還是挺大的。
而布隆過濾器就不用爲每個數都分配空間了,而是直接把所有的數通過算法映射到同一個數組,帶來的問題就是衝突上升,只要概率在可以接受的範圍,用時間換空間,在很多時候是好方案。布隆過濾器需要的空間僅爲HashMap的1/8-1/4之間,而且它不會漏掉任何一個在黑名單的可疑對象,問題只是會誤傷一些非黑名單對象。

原理

初始化狀態是一個全爲0的bit數組

爲了表達存儲N個元素的集合,使用K個獨立的函數來進行哈希運算。x1,x2……xk爲k個哈希算法。
如果集合元素有N1,N2……NN,N1經過x1運算後得到的結果映射的位置標1,經過x2運算後結果映射也標1,已經爲1的報錯1不變。經過k次散列後,對N1的散列完成。
依次對N2,NN等所有數據進行散列,最終得到一個部分爲1,部分位爲0的字節數組。當然了,這個字節數組會比較長,不然散列效果不好。
那麼怎麼判斷一個外來的元素是否已經在集合裏呢,譬如已經散列了10億個垃圾郵箱,現在來了一個郵箱,怎麼判斷它是否在這10億裏面呢?
很簡單,就拿這個新來的也依次經歷x1,x2……xk個哈希算法即可。
在任何一個哈希算法譬如到x2時,得到的映射值有0,那就說明這個郵箱肯定不在這10億內。
如果是一個黑名單對象,那麼可以肯定的是所有映射都爲1,肯定跑不了它。也就是說是壞人,一定會被抓。
那麼誤傷是爲什麼呢,就是指一些非黑名單對象的值經過k次哈希後,也全部爲1,但它確實不是黑名單裏的值,這種概率是存在的,但是是可控的。





上面的幾個圖看起來很高深,但那不是我們關心的問題,歸根到底意思其實就是你想讓錯誤率降低,就得增大數組的長度,就是這樣。
我們使用BloomFilter的目的就是想省空間,所以我們需要做的就是在錯誤率上做個權衡就OK。
很多時候這個錯誤率我們是能接受的,譬如垃圾郵箱問題,是壞人一定會被抓,這個能保證。無非是一些好人也被抓,這個可以通過給這些可伶的被誤傷的設置個白名單就OK。至於爬蟲Url重複這個就更沒問題了,會缺掉一些網頁而已。
至於在緩存穿透上的應用,是爲了避免惡意用戶頻繁請求緩存中不存在DB也不存在的值,會導致緩存失效、DB負載過大,可以使用BloomFilter把所有數據放到bit數組中,當用戶請求時存在的值肯定能放行,部分不存在的值也會被放行,絕大部分會被攔截,這些少量漏網之魚對於DB的影響就會比大量穿透好的多了。

講了這麼多,可以看到,原理很簡單,但要實際做一個BloomFilter可就麻煩了,已經屬於科學家的範疇了,好在早早有人已經搞定了java版的實現,用法很簡單,下一篇看看。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章