您好,登錄后才能下訂單哦!
本篇內容主要講解“redis緩存穿透怎么理解”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“redis緩存穿透怎么理解”吧!
布隆過濾器(英語:Bloom Filter)是1970年由一個叫布隆的小伙子提出的。它實際上是一個很長的二進制向量和一系列隨機映射函數。布隆過濾器可以用于檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困難。
布隆過濾器的原理是,當一個元素被加入集合時,通過K個散列函數將這個元素映射成一個位數組中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約)知道集合中有沒有它了:如果這些點有任何一個0,則被檢元素一定不在;如果都是1,則被檢元素很可能在。這就是布隆過濾器的基本思想。
Bloom Filter跟單哈希函數Bit-Map不同之處在于:Bloom Filter使用了k個哈希函數,每個字符串跟k個bit對應。從而降低了沖突的概率。
由預估數據量n以及bit數組長度m,可以得到一個hash函數的個數k:
哈希函數的選擇對性能的影響應該是很大的,一個好的哈希函數要能近似等概率的將字符串映射到各個Bit。選擇k個不同的哈希函數比較麻煩,一種簡單的方法是選擇一個哈希函數,然后送入k個不同的參數。
哈希函數個數k、位數組大小m、加入的字符串數量n的關系可以參考Bloom Filters - the math,Bloom_filter-wikipedia
要使用BloomFilter,需要引入guava包:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.0</version> </dependency>
測試分兩步:
1、往過濾器中放一百萬個數,然后去驗證這一百萬個數是否能通過過濾器
2、另外找一萬個數,去檢驗漏網之魚的數量
/** * 測試布隆過濾器(可用于redis緩存穿透) */ public class TestBloomFilter { private static int total = 1000000; private static BloomFilter<Integer> bf = BloomFilter.create(Funnels.integerFunnel(), total); // private static BloomFilter<Integer> bf = BloomFilter.create(Funnels.integerFunnel(), total, 0.001); public static void main(String[] args) { // 初始化1000000條數據到過濾器中 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("誤傷的數量:" + count); } }
運行結果:
運行結果表示,遍歷這一百萬個在過濾器中的數時,都被識別出來了。一萬個不在過濾器中的數,誤傷了320個,錯誤率是0.03左右。
看下BloomFilter的源碼:
public static <T> BloomFilter<T> create(Funnel<? super T> funnel, int expectedInsertions) { return create(funnel, (long) expectedInsertions); } public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions) { return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions } public static <T> BloomFilter<T> create( Funnel<? super T> funnel, long expectedInsertions, double fpp) { return create(funnel, expectedInsertions, fpp, BloomFilterStrategies.MURMUR128_MITZ_64); } static <T> BloomFilter<T> create( Funnel<? super T> funnel, long expectedInsertions, double fpp, Strategy strategy) { ...... }
BloomFilter一共四個create方法,不過最終都是走向第四個。看一下每個參數的含義:
funnel:數據類型(一般是調用Funnels工具類中的)
expectedInsertions:期望插入的值的個數
fpp 錯誤率(默認值為0.03)
strategy 哈希算法(我也不懂啥意思)Bloom Filter的應用
在最后一個create方法中,設置一個斷點:
上面的numBits,表示存一百萬個int類型數字,需要的位數為7298440,700多萬位。理論上存一百萬個數,一個int是4字節32位,需要481000000=3200萬位。如果使用HashMap去存,按HashMap50%的存儲效率,需要6400萬位。可以看出BloomFilter的存儲空間很小,只有HashMap的1/10左右
上面的numHashFunctions,表示需要5個函數去存這些數字
使用第三個create方法,我們設置下錯誤率:
private static BloomFilter<Integer> bf = BloomFilter.create(Funnels.integerFunnel(), total, 0.0003);
再運行看看:
當錯誤率設為0.0003時,所需要的位數為16883499,1600萬位,需要12個函數
和上面對比可以看出,錯誤率越大,所需空間和時間越小,錯誤率越小,所需空間和時間約大
常見的幾個應用場景:
cerberus在收集監控數據的時候, 有的系統的監控項量會很大, 需要檢查一個監控項的名字是否已經被記錄到db過了, 如果沒有的話就需要寫入db.
爬蟲過濾已抓到的url就不再抓,可用bloom filter過濾
垃圾郵件過濾。如果用哈希表,每存儲一億個 email地址,就需要 1.6GB的內存(用哈希表實現的具體辦法是將每一個 email地址對應成一個八字節的信息指紋,然后將這些信息指紋存入哈希表,由于哈希表的存儲效率一般只有 50%,因此一個 email地址需要占用十六個字節。一億個地址大約要 1.6GB,即十六億字節的內存)。因此存貯幾十億個郵件地址可能需要上百 GB的內存。而Bloom Filter只需要哈希表 1/8到 1/4 的大小就能解決同樣的問題。
到此,相信大家對“redis緩存穿透怎么理解”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。