布隆過(guò)濾器的原理衔峰、使用場(chǎng)景和注意事項(xiàng)

原文鏈接:http://www.reibang.com/p/2104d11ee0a2

今天碰到個(gè)業(yè)務(wù)佩脊,他的 Redis 集群有個(gè)大 Value 用途是作為布隆過(guò)濾器,但溝通的時(shí)候被小懟了一下垫卤,意思大概是?“布隆過(guò)濾器原理都不懂威彰,還要我優(yōu)化?”穴肘。技術(shù)菜被人懟認(rèn)了歇盼、怪不得別人,自己之前確實(shí)只是聽(tīng)說(shuō)過(guò)這個(gè)评抚,但是沒(méi)深入了解過(guò)豹缀,趁這個(gè)機(jī)會(huì)補(bǔ)充一下知識(shí)。

在進(jìn)入正文之前慨代,之前看到的有句話我覺(jué)得說(shuō)得很好:

Data structures are nothing different. They are like the bookshelves of your application where you can organize your data. Different data structures will give you different facility and benefits. To properly use the power and accessibility of the data structures you need to know the trade-offs of using one.

大意是不同的數(shù)據(jù)結(jié)構(gòu)有不同的適用場(chǎng)景和優(yōu)缺點(diǎn)耿眉,你需要仔細(xì)權(quán)衡自己的需求之后妥善適用它們,布隆過(guò)濾器就是踐行這句話的代表鱼响。

什么是布隆過(guò)濾器

本質(zhì)上布隆過(guò)濾器是一種數(shù)據(jù)結(jié)構(gòu),比較巧妙的概率型數(shù)據(jù)結(jié)構(gòu)(probabilistic data structure)组底,特點(diǎn)是高效地插入和查詢丈积,可以用來(lái)告訴你 “某樣?xùn)|西一定不存在或者可能存在”筐骇。

相比于傳統(tǒng)的 List、Set江滨、Map 等數(shù)據(jù)結(jié)構(gòu)铛纬,它更高效、占用空間更少唬滑,但是缺點(diǎn)是其返回的結(jié)果是概率性的告唆,而不是確切的。

實(shí)現(xiàn)原理

HashMap 的問(wèn)題

講述布隆過(guò)濾器的原理之前晶密,我們先思考一下擒悬,通常你判斷某個(gè)元素是否存在用的是什么?應(yīng)該蠻多人回答 HashMap 吧稻艰,確實(shí)可以將值映射到 HashMap 的 Key懂牧,然后可以在 O(1) 的時(shí)間復(fù)雜度內(nèi)返回結(jié)果,效率奇高尊勿。但是 HashMap 的實(shí)現(xiàn)也有缺點(diǎn)僧凤,例如存儲(chǔ)容量占比高,考慮到負(fù)載因子的存在元扔,通城#空間是不能被用滿的,而一旦你的值很多例如上億的時(shí)候澎语,那 HashMap 占據(jù)的內(nèi)存大小就變得很可觀了途事。

還比如說(shuō)你的數(shù)據(jù)集存儲(chǔ)在遠(yuǎn)程服務(wù)器上,本地服務(wù)接受輸入咏连,而數(shù)據(jù)集非常大不可能一次性讀進(jìn)內(nèi)存構(gòu)建 HashMap 的時(shí)候盯孙,也會(huì)存在問(wèn)題。

布隆過(guò)濾器數(shù)據(jù)結(jié)構(gòu)

布隆過(guò)濾器是一個(gè) bit 向量或者說(shuō) bit 數(shù)組祟滴,長(zhǎng)這樣:

image

如果我們要映射一個(gè)值到布隆過(guò)濾器中振惰,我們需要使用多個(gè)不同的哈希函數(shù)生成多個(gè)哈希值,并對(duì)每個(gè)生成的哈希值指向的 bit 位置 1垄懂,例如針對(duì)值 “baidu” 和三個(gè)不同的哈希函數(shù)分別生成了哈希值 1骑晶、4、7草慧,則上圖轉(zhuǎn)變?yōu)椋?/p>

image

Ok桶蛔,我們現(xiàn)在再存一個(gè)值 “tencent”,如果哈希函數(shù)返回 3漫谷、4仔雷、8 的話,圖繼續(xù)變?yōu)椋?/p>

image

值得注意的是碟婆,4 這個(gè) bit 位由于兩個(gè)值的哈希函數(shù)都返回了這個(gè) bit 位电抚,因此它被覆蓋了∈玻現(xiàn)在我們?nèi)绻氩樵?“dianping” 這個(gè)值是否存在,哈希函數(shù)返回了 1公给、5借帘、8三個(gè)值,結(jié)果我們發(fā)現(xiàn) 5 這個(gè) bit 位上的值為 0肺然,說(shuō)明沒(méi)有任何一個(gè)值映射到這個(gè) bit 位上匣沼,因此我們可以很確定地說(shuō) “dianping” 這個(gè)值不存在狰挡。而當(dāng)我們需要查詢 “baidu” 這個(gè)值是否存在的話,那么哈希函數(shù)必然會(huì)返回 1释涛、4加叁、7,然后我們檢查發(fā)現(xiàn)這三個(gè) bit 位上的值均為 1它匕,那么我們可以說(shuō) “baidu” 存在了么窖认?答案是不可以,只能是 “baidu” 這個(gè)值可能存在烧给。

這是為什么呢喝噪?答案跟簡(jiǎn)單础嫡,因?yàn)殡S著增加的值越來(lái)越多酝惧,被置為 1 的 bit 位也會(huì)越來(lái)越多,這樣某個(gè)值 “taobao” 即使沒(méi)有被存儲(chǔ)過(guò)巫财,但是萬(wàn)一哈希函數(shù)返回的三個(gè) bit 位都被其他值置位了 1 哩陕,那么程序還是會(huì)判斷 “taobao” 這個(gè)值存在赫舒。

支持刪除么

目前我們知道布隆過(guò)濾器可以支持 add 和 isExist 操作闽瓢,那么 delete 操作可以么,答案是不可以,例如上圖中的 bit 位 4 被兩個(gè)值共同覆蓋的話园担,一旦你刪除其中一個(gè)值例如 “tencent” 而將其置位 0,那么下次判斷另一個(gè)值例如 “baidu” 是否存在的話艰山,會(huì)直接返回 false咏闪,而實(shí)際上你并沒(méi)有刪除它。

如何解決這個(gè)問(wèn)題纵装,答案是計(jì)數(shù)刪除据某。但是計(jì)數(shù)刪除需要存儲(chǔ)一個(gè)數(shù)值,而不是原先的 bit 位癣籽,會(huì)增大占用的內(nèi)存大小。這樣的話瓶籽,增加一個(gè)值就是將對(duì)應(yīng)索引槽上存儲(chǔ)的值加一埂材,刪除則是減一,判斷是否存在則是看值是否大于0楞遏。

如何選擇哈希函數(shù)個(gè)數(shù)和布隆過(guò)濾器長(zhǎng)度

很顯然寡喝,過(guò)小的布隆過(guò)濾器很快所有的 bit 位均為 1,那么查詢?nèi)魏沃刀紩?huì)返回“可能存在”预鬓,起不到過(guò)濾的目的了赊颠。布隆過(guò)濾器的長(zhǎng)度會(huì)直接影響誤報(bào)率劈彪,布隆過(guò)濾器越長(zhǎng)其誤報(bào)率越小。

另外痘括,哈希函數(shù)的個(gè)數(shù)也需要權(quán)衡滔吠,個(gè)數(shù)越多則布隆過(guò)濾器 bit 位置位 1 的速度越快,且布隆過(guò)濾器的效率越低翰舌;但是如果太少的話冬骚,那我們的誤報(bào)率會(huì)變高。

image

k 為哈希函數(shù)個(gè)數(shù)庇麦,m 為布隆過(guò)濾器長(zhǎng)度属愤,n 為插入的元素個(gè)數(shù),p 為誤報(bào)率住诸。

至于如何推導(dǎo)這個(gè)公式,我在知乎發(fā)布的文章有涉及丧诺,感興趣可以看看奄薇,不感興趣的話記住上面這個(gè)公式就行了。

最佳實(shí)踐

常見(jiàn)的適用常見(jiàn)有呵晚,利用布隆過(guò)濾器減少磁盤 IO 或者網(wǎng)絡(luò)請(qǐng)求沫屡,因?yàn)橐坏┮粋€(gè)值必定不存在的話,我們可以不用進(jìn)行后續(xù)昂貴的查詢請(qǐng)求沮脖。

另外,既然你使用布隆過(guò)濾器來(lái)加速查找和判斷是否存在驶俊,那么性能很低的哈希函數(shù)不是個(gè)好選擇,推薦 MurmurHash榕酒、Fnv 這些故俐。

大Value拆分

Redis 因其支持 setbit 和 getbit 操作,且純內(nèi)存性能高等特點(diǎn),因此天然就可以作為布隆過(guò)濾器來(lái)使用肩榕。但是布隆過(guò)濾器的不當(dāng)使用極易產(chǎn)生大 Value,增加 Redis 阻塞風(fēng)險(xiǎn)筐乳,因此生成環(huán)境中建議對(duì)體積龐大的布隆過(guò)濾器進(jìn)行拆分乔妈。

拆分的形式方法多種多樣,但是本質(zhì)是不要將 Hash(Key) 之后的請(qǐng)求分散在多個(gè)節(jié)點(diǎn)的多個(gè)小 bitmap 上勃刨,而是應(yīng)該拆分成多個(gè)小 bitmap 之后股淡,對(duì)一個(gè) Key 的所有哈希函數(shù)都落在這一個(gè)小 bitmap 上。

參考資料

probabilistic data structures:bloom filter

bloom filters

本文遵守創(chuàng)作共享?CC BY-NC-SA 3.0協(xié)議

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贾铝,一起剝皮案震驚了整個(gè)濱河市埠帕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌敛瓷,老刑警劉巖琐驴,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秤标,死亡現(xiàn)場(chǎng)離奇詭異宙刘,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)衙猪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門布近,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人棵譬,你說(shuō)我怎么就攤上這事预伺。” “怎么了脏嚷?”我有些...
    開(kāi)封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵瞒御,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我趾唱,道長(zhǎng)蜻懦,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任带欢,我火速辦了婚禮烤惊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘渡贾。我一直安慰自己雄右,他們只是感情好纺讲,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布囤屹。 她就那樣靜靜地躺著,像睡著了一般乡括。 火紅的嫁衣襯著肌膚如雪智厌。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天敷扫,我揣著相機(jī)與錄音诚卸,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛脊髓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播恭朗,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼依疼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了膀值?” 一聲冷哼從身側(cè)響起误辑,我...
    開(kāi)封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤巾钉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后砰苍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體阱高,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赤惊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年寒屯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片处面。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡菩掏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出野揪,到底是詐尸還是另有隱情瞧栗,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布挣惰,位于F島的核電站殴边,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏锤岸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一拳氢、第九天 我趴在偏房一處隱蔽的房頂上張望蛋铆。 院中可真熱鬧,春花似錦栗恩、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蒙兰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間采缚,已是汗流浹背挠他。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贸呢,地道東北人拢军。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像固蛾,于是被迫代替她去往敵國(guó)和親赌渣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昌犹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容