<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          what? 還不知道布隆過濾器嗎?

          共 2147字,需瀏覽 5分鐘

           ·

          2021-12-15 10:32

          4bd29cc200d33ca14dee70bbb68ea733.webp

          前言

          在好早之前,我在看面試寶典的時(shí)候,關(guān)于預(yù)防緩存雪崩,其中有一個(gè)解決方案就是在緩存前面增加布隆過濾器,時(shí)至今日,我依然清晰地記著布隆過濾器,但是卻不曾深入的了解它,所以今天我想花一點(diǎn)時(shí)間來詳細(xì)了解下布隆過濾器。

          布隆過濾器

          什么是布隆過濾器?

          簡(jiǎn)單來說,布隆過濾器是一種算法,用于判斷某個(gè)值是否在一個(gè)集合中。

          通常來說,我們要判斷一個(gè)值是否存在集合中,我們是需要將目標(biāo)值和集合中的每個(gè)值進(jìn)行比較,最終確定是否包含,這樣的缺點(diǎn)也很明顯,如果數(shù)據(jù)量本身很龐大的話,我們需要存儲(chǔ)的數(shù)據(jù)量會(huì)很多,而且比較的時(shí)候也會(huì)比較耗時(shí)。

          相比而言,布隆過濾器的設(shè)計(jì)就獨(dú)特了很多,它通過一個(gè)Hash函數(shù)將一個(gè)元素映射成一個(gè)位陣列(Bit array)中的一個(gè)點(diǎn)。這樣一來,我們只要看看這個(gè)點(diǎn)是不是1就可以知道集合中有沒有它了,這就是布隆過濾器的基本思想。

          但是Hash面臨的最大問題就是hash沖突。假設(shè)Hash函數(shù)是良好的,如果我們的位陣列長度為m個(gè)點(diǎn),那么如果我們想將沖突率降低到例如 1%,這個(gè)散列表就只能容納m / 100個(gè)元素。顯然這就不叫空間效率了(Space-efficient)了。解決方法也簡(jiǎn)單,就是使用多個(gè)Hash,如果它們有一個(gè)說元素不在集合中,那肯定就不在。如果它們都說在,雖然也有一定可能性它們?cè)谡f謊,不過直覺上判斷這種事情的概率是比較低的,這個(gè)概率我們通常稱之為誤差率。

          所以,簡(jiǎn)單總結(jié)下,布隆過濾器其實(shí)就是通過hash來描述一個(gè)數(shù)據(jù),然后保存該數(shù)據(jù)的hash值,從而實(shí)現(xiàn)數(shù)據(jù)的判斷,但是由于hash的沖突(具體取決于hash表的大小),會(huì)導(dǎo)致數(shù)據(jù)的誤判,所以本質(zhì)上我們布隆過濾器的誤判是由于hash表的有限性。

          關(guān)于hash

          hash算法我這里不打算展開(目前我也不是很熟悉i??),但是我這里想要通過一個(gè)簡(jiǎn)單的示例,來解釋下什么是hash

          我們小學(xué)二年級(jí)的時(shí)候,學(xué)過平面上兩個(gè)坐標(biāo)可以確定唯一一個(gè)點(diǎn)(坐標(biāo)),而我們判斷兩個(gè)點(diǎn)是否是同一個(gè)點(diǎn),是可以通過坐標(biāo)對(duì)比來實(shí)現(xiàn),而hash算法其實(shí)本身就相當(dāng)于一套坐標(biāo)系,通過這套坐標(biāo)系理論上我們是可以描述所有數(shù)據(jù),且可以確定數(shù)據(jù)的唯一性(當(dāng)然具體取決于hash表大小)。

          另外一種hash的典型應(yīng)用就是我們的身份證,每個(gè)人的身份證號(hào)就是我們每個(gè)人的hash code,通過這個(gè)hash code就可以在14億人中確定唯一的你,所以身份證號(hào)算法就是一種類似于hash的算法。

          博隆過濾器的應(yīng)用

          上面其實(shí)我們已經(jīng)列舉了博隆過濾器的典型應(yīng)用場(chǎng)景——校驗(yàn)?zāi)硞€(gè)數(shù)據(jù)是否存在,所以我們經(jīng)常把他用在一些需要進(jìn)行數(shù)據(jù)否存在的校驗(yàn)上,最典型的就是用在緩存的key的判斷上,作為緩存系統(tǒng)最后的屏障。

          在通常的系統(tǒng)開發(fā)中,我們經(jīng)常要用到緩存組件,而緩存中最核心的一個(gè)場(chǎng)景就是查詢,而緩存查詢中操作頻次最高就是判斷某個(gè)key是否存在,正常情況下簡(jiǎn)單的業(yè)務(wù)判斷是沒有問題的,就算批量很大,也不會(huì)出現(xiàn)大批量key不存在的情況,但是如果遇到惡意攻擊時(shí),一切都變得不那么確定了,比如有人發(fā)送大量惡意請(qǐng)求專門查詢不存在的key,這時(shí)候就會(huì)導(dǎo)致redis服務(wù)不可用,從而導(dǎo)致緩存雪崩。

          這時(shí)候如果我們用了布隆過濾器這樣的組件,這樣的問題就不會(huì)影響如此嚴(yán)重,因?yàn)椴悸∵^濾器可以幫我們屏蔽到絕大多數(shù)的請(qǐng)求,從而降低redis雪崩的風(fēng)險(xiǎn)。

          關(guān)于布隆過濾器的實(shí)現(xiàn),網(wǎng)上其實(shí)有很多實(shí)現(xiàn),但最典型的當(dāng)屬guava包中提供的BloomFilter。要說guava真是個(gè)好用的工具包,提供了各種各樣好用的工具,比如限流組件、容器組件以及今天我們分享的布隆過濾器,下面我們看下如何使用BloomFilter

          由于BloomFilter的構(gòu)造方案是私有的,所以我們沒有辦法通過new的方式實(shí)例化BloomFilter,但是官方提供了實(shí)例化的方式——create方法:

          5b80e5d79b4982fdc4cb136bcd3e456b.webp

          其他的create方法都是在此基礎(chǔ)上做的封裝,所以我們只簡(jiǎn)單分析上面這個(gè)方法。

          這個(gè)方案有四個(gè)參數(shù):

          • Funnel表示我們要過濾的數(shù)據(jù)類別,它相當(dāng)于我們的漏斗,也算是容器,用于判斷數(shù)據(jù)是否存在,目前在Funnels類中提供了六種實(shí)現(xiàn),應(yīng)該可以滿足我們絕大多數(shù)場(chǎng)景;
          b336738ade1c256cedd5c6bb578bf60e.webp
          • expectedInsertions表示預(yù)期樣本,也就類似于我們前面說的hash表的大小,如果該數(shù)據(jù)太小,誤差率會(huì)很大,原則上來說,這個(gè)數(shù)要大于等于我們要判斷的樣本數(shù)量,否則沒有辦法保證準(zhǔn)確度,當(dāng)然也不能太大,過大會(huì)有性能問題

          • fpp表示誤差率,默認(rèn)是0.003

            8cc138e8fd1437f3dc116dc2dc8d9b00.webp

          下面是一個(gè)簡(jiǎn)單的示例

          public?class?BloomFilterTest?{
          ????public?static?void?main(String[]?args)?{
          ????????Funnel?charSequenceFunnel?=?Funnels.stringFunnel(Charset.defaultCharset());
          ????????String?test?=?"hello";
          ????????BloomFilter?bloomFilter?=?BloomFilter.create(charSequenceFunnel,?100);
          ????????for?(int?i?=?0;?i?100;?i++)?{
          ????????????bloomFilter.put(test?+?i);
          ????????}
          ????????String?object?=?test?+?-888;
          ????????if?(bloomFilter.mightContain(object))?{
          ????????????System.out.println("包含"?+?object);
          ????????}?else?{
          ????????????System.out.println("不包含"?+?object);
          ????????}
          ????}
          }

          正常情況下,會(huì)打印輸入不包含hello-888

          dd5a9a4bef3bbd2cb66809b790745fcc.webp

          但是如果我將樣本數(shù)量變小或者將數(shù)據(jù)量變大,這時(shí)候就會(huì)出現(xiàn)誤判的情況。

          比如這里我判斷的是hello-888,bloomFilter中保存的應(yīng)該是hello0hello999,應(yīng)該是不存在才對(duì),但是由于hash表(代稱)不夠大,所以會(huì)出現(xiàn)數(shù)據(jù)描述精度丟失問題:

          681da4ac2ac89fd47f6505204a76e3b3.webp

          但是如果樣本數(shù)量和數(shù)據(jù)本身數(shù)量差別不大時(shí),則不會(huì)出現(xiàn)這種情況。

          擴(kuò)展

          Redis v4.0 ?之后的版本有了 Module(模塊/插件) 功能,Redis Modules 可以讓 Redis 通過使用外部模塊擴(kuò)展其功能 ,而布隆過濾器就是其中的 Module。詳情可以查看 Redis 官方對(duì) Redis Modules 的介紹 :

          https://redis.io/modules

          另外,官網(wǎng)推薦了一個(gè)RedisBloom 作為 Redis 布隆過濾器的Module,地址:

          https://github.com/RedisBloom/RedisBloom

          另外,redis客戶端工具Redisson也提供了布隆過濾器的實(shí)現(xiàn),其底層使用數(shù)據(jù)結(jié)構(gòu)是bitMap,有興趣的小伙伴可以去了解下。

          結(jié)語

          布隆過濾器這個(gè)東東,已經(jīng)在我心頭縈繞了很久了,但是一直都沒有花時(shí)間探索過,對(duì)它只能算知道有這么個(gè)組件,知道它的大概用途,但是對(duì)于它的原理和實(shí)現(xiàn)邏輯,卻不曾了解。今天抽時(shí)間做一次簡(jiǎn)單的探索,也算是搞清楚了布隆過濾器的應(yīng)用場(chǎng)景和簡(jiǎn)單的實(shí)現(xiàn)原理,當(dāng)然也清楚了自己在數(shù)據(jù)底層的短板,比如數(shù)據(jù)結(jié)構(gòu)——散列,說明我也該好好補(bǔ)下數(shù)據(jù)結(jié)構(gòu)這塊的知識(shí)了,數(shù)據(jù)結(jié)構(gòu)那本書該翻一翻了??,好了,今天就到這里吧,各位小伙伴,晚安吧!

          - END -


          瀏覽 53
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲国产一级黄片 | 在线观看亚洲视频 | 男女操逼视频网站入口免费观看1草溜 | 男人天堂网av | 丰满熟妇中文字幕精品 |