BloomFilter能解決什么問(wèn)題
在我們對(duì)查詢(xún)語(yǔ)句添加緩存的情況中,會(huì)存在緩存穿透的情況,即請(qǐng)求方故意以一種不存在的key進(jìn)行查詢(xún),導(dǎo)致每次請(qǐng)求都無(wú)法命中緩存,請(qǐng)求都打到數(shù)據(jù)庫(kù),可能會(huì)把數(shù)據(jù)庫(kù)給打掛掉.
對(duì)于這種緩存穿透的情況,我們有如下的方案:
1.數(shù)據(jù)返回為空的話(huà),我們將空數(shù)據(jù)也緩存在緩存中.
但是這種情況會(huì)存在一個(gè)問(wèn)題,如果請(qǐng)求每次來(lái)查詢(xún)的都是不同的不存在的key,這些請(qǐng)求還是會(huì)打到數(shù)據(jù)庫(kù)層面,并且緩存中緩存了大量的空對(duì)象.這種方案治標(biāo)不治本
2.使用BloomFilter,BloomFilter存儲(chǔ)著所有的key,如果key在BloomFilter中不存在,則一定不存在.但是BloomFilter存在誤判的情況.即如果key在BloomFilter中存在,可能不存在,這時(shí)候再去走緩存,查數(shù)據(jù)庫(kù),但是這時(shí)候已經(jīng)過(guò)濾了絕大多數(shù)的key,打到數(shù)據(jù)庫(kù)的key已經(jīng)很少了.
那BloomFilter的底層實(shí)現(xiàn)原理到底是怎么樣的呢?
首先我們先看下Guava里的BloomFilter
需要引入的jar包
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
BloomFilter<Integer> integerBloomFilter = BloomFilter.create(Funnels.integerFunnel(), 1000, 0.01d);
這樣便創(chuàng)建了一個(gè)BloomFilter番舆。參數(shù)含義如下:
1.第一個(gè)參數(shù)指的是BloomFilter中塞入的數(shù)據(jù)類(lèi)型
2.第二個(gè)參數(shù)指的是期望的大小
3.第三個(gè)參數(shù)指的是容錯(cuò)的概率(不能等于0)
BloomFilter底層是bitmap形式忽孽,所以所占的內(nèi)存比我們常用的hashmap小很多,所以可以存放大量數(shù)據(jù)蜀涨。
總的來(lái)說(shuō)瘫析,數(shù)據(jù)存入BloomFilter時(shí)伟件,通過(guò)K個(gè)hash函數(shù)蛙粘,將數(shù)據(jù)進(jìn)行hash过牙,然后將制定槽位的數(shù)據(jù)置為1。容錯(cuò)概率越小粪薛,K值越大悴了,最后實(shí)際BloomFilter的大小也就越大。
BloomFilter判斷該值是否存在违寿,還是將該值通過(guò)K個(gè)hash函數(shù)進(jìn)行hash湃交,如果K個(gè)hash值的每個(gè)槽位的值都為1,則該數(shù)據(jù)可能存在藤巢,因?yàn)閔ash是有hash碰撞的情況的搞莺。如果有個(gè)槽位不為1,則該值就一定不存在掂咒。
相應(yīng)的才沧,如果我們的服務(wù)有多個(gè)集群,那么Guava的BloomFilter就不是很適用了绍刮,我們可以使用redis的BitMap結(jié)構(gòu)來(lái)進(jìn)行處理温圆。