本篇內(nèi)容主要講解“redis緩存穿透怎么理解”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“redis緩存穿透怎么理解”吧!
創(chuàng)新互聯(lián)建站主營南樂網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP軟件開發(fā),南樂h5重慶小程序開發(fā)搭建,南樂網(wǎng)站營銷推廣歡迎南樂等地區(qū)企業(yè)咨詢
布隆過濾器(英語:Bloom Filter)是1970年由一個叫布隆的小伙子提出的。它實際上是一個很長的二進制向量和一系列隨機映射函數(shù)。布隆過濾器可以用于檢索一個元素是否在一個集合中。它的優(yōu)點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困難。
布隆過濾器的原理是,當(dāng)一個元素被加入集合時,通過K個散列函數(shù)將這個元素映射成一個位數(shù)組中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約)知道集合中有沒有它了:如果這些點有任何一個0,則被檢元素一定不在;如果都是1,則被檢元素很可能在。這就是布隆過濾器的基本思想。
Bloom Filter跟單哈希函數(shù)Bit-Map不同之處在于:Bloom Filter使用了k個哈希函數(shù),每個字符串跟k個bit對應(yīng)。從而降低了沖突的概率。
由預(yù)估數(shù)據(jù)量n以及bit數(shù)組長度m,可以得到一個hash函數(shù)的個數(shù)k:
哈希函數(shù)的選擇對性能的影響應(yīng)該是很大的,一個好的哈希函數(shù)要能近似等概率的將字符串映射到各個Bit。選擇k個不同的哈希函數(shù)比較麻煩,一種簡單的方法是選擇一個哈希函數(shù),然后送入k個不同的參數(shù)。
哈希函數(shù)個數(shù)k、位數(shù)組大小m、加入的字符串?dāng)?shù)量n的關(guān)系可以參考Bloom Filters - the math,Bloom_filter-wikipedia
要使用BloomFilter,需要引入guava包:
com.google.guava guava 23.0
測試分兩步:
1、往過濾器中放一百萬個數(shù),然后去驗證這一百萬個數(shù)是否能通過過濾器
2、另外找一萬個數(shù),去檢驗漏網(wǎng)之魚的數(shù)量
/** * 測試布隆過濾器(可用于redis緩存穿透) */ public class TestBloomFilter { private static int total = 1000000; private static BloomFilterbf = BloomFilter.create(Funnels.integerFunnel(), total); // private static BloomFilter bf = BloomFilter.create(Funnels.integerFunnel(), total, 0.001); public static void main(String[] args) { // 初始化1000000條數(shù)據(jù)到過濾器中 for (int i = 0; i < total; i++) { bf.put(i); } // 匹配已在過濾器中的值,是否有匹配不上的 for (int i = 0; i < total; i++) { if (!bf.mightContain(i)) { System.out.println("有壞人逃脫了~~~"); } } // 匹配不在過濾器中的10000個值,有多少匹配出來 int count = 0; for (int i = total; i < total + 10000; i++) { if (bf.mightContain(i)) { count++; } } System.out.println("誤傷的數(shù)量:" + count); } }
運行結(jié)果:
運行結(jié)果表示,遍歷這一百萬個在過濾器中的數(shù)時,都被識別出來了。一萬個不在過濾器中的數(shù),誤傷了320個,錯誤率是0.03左右。
看下BloomFilter的源碼:
public staticBloomFilter create(Funnel super T> funnel, int expectedInsertions) { return create(funnel, (long) expectedInsertions); } public static BloomFilter create(Funnel super T> funnel, long expectedInsertions) { return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions } public static BloomFilter create( Funnel super T> funnel, long expectedInsertions, double fpp) { return create(funnel, expectedInsertions, fpp, BloomFilterStrategies.MURMUR128_MITZ_64); } static BloomFilter create( Funnel super T> funnel, long expectedInsertions, double fpp, Strategy strategy) { ...... }
BloomFilter一共四個create方法,不過最終都是走向第四個??匆幌旅總€參數(shù)的含義:
funnel:數(shù)據(jù)類型(一般是調(diào)用Funnels工具類中的)
expectedInsertions:期望插入的值的個數(shù)
fpp 錯誤率(默認值為0.03)
strategy 哈希算法(我也不懂啥意思)Bloom Filter的應(yīng)用
在最后一個create方法中,設(shè)置一個斷點:
上面的numBits,表示存一百萬個int類型數(shù)字,需要的位數(shù)為7298440,700多萬位。理論上存一百萬個數(shù),一個int是4字節(jié)32位,需要481000000=3200萬位。如果使用HashMap去存,按HashMap50%的存儲效率,需要6400萬位。可以看出BloomFilter的存儲空間很小,只有HashMap的1/10左右
上面的numHashFunctions,表示需要5個函數(shù)去存這些數(shù)字
使用第三個create方法,我們設(shè)置下錯誤率:
private static BloomFilterbf = BloomFilter.create(Funnels.integerFunnel(), total, 0.0003);
再運行看看:
當(dāng)錯誤率設(shè)為0.0003時,所需要的位數(shù)為16883499,1600萬位,需要12個函數(shù)
和上面對比可以看出,錯誤率越大,所需空間和時間越小,錯誤率越小,所需空間和時間約大
常見的幾個應(yīng)用場景:
cerberus在收集監(jiān)控數(shù)據(jù)的時候, 有的系統(tǒng)的監(jiān)控項量會很大, 需要檢查一個監(jiān)控項的名字是否已經(jīng)被記錄到db過了, 如果沒有的話就需要寫入db.
爬蟲過濾已抓到的url就不再抓,可用bloom filter過濾
垃圾郵件過濾。如果用哈希表,每存儲一億個 email地址,就需要 1.6GB的內(nèi)存(用哈希表實現(xiàn)的具體辦法是將每一個 email地址對應(yīng)成一個八字節(jié)的信息指紋,然后將這些信息指紋存入哈希表,由于哈希表的存儲效率一般只有 50%,因此一個 email地址需要占用十六個字節(jié)。一億個地址大約要 1.6GB,即十六億字節(jié)的內(nèi)存)。因此存貯幾十億個郵件地址可能需要上百 GB的內(nèi)存。而Bloom Filter只需要哈希表 1/8到 1/4 的大小就能解決同樣的問題。
到此,相信大家對“redis緩存穿透怎么理解”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!