預防緩存擊穿-布隆過濾器

布隆過濾器之防止緩存擊穿

爲何使用布隆過濾器

  • 布隆過濾器能夠用於檢索一個元素是否在一個集合中的重要工具,具備快速,比哈希表更節省空間等優勢,而缺點在於有必定的誤識別率
  • 布隆過濾器(bloom filter)是Google Guava類庫裏面的組件
  • 當代換聯網環境下使用緩存的公司可說遍地都是你們都知道使用緩存就是爲了緩存一些冷數據以減小數據庫壓力
  • 查詢一些緩存不存在的數據 透過緩存直接查詢數據庫
  • 服務報錯

布隆過濾器介紹

  • bloom算法相似一個hash set,用來判斷某個元素(key)是否在某個集合中和通常的hash set不一樣的是,這個算法無需存儲key的值,對於每一個key,只須要k個比特位,每一個存儲一個標誌,用來判斷key是否在集合中
  • 初始化時會初始化一個長度爲n比特的數組,每一個比特位初始化爲0(n值個數由誤判率決定,誤判率越小則n值越大,誤判率越大則n值越小)
  • 某個key加入集合時,用k個hash函數計算出k個散列值,並把數組中對應的比特位置爲1
  • 判斷某個key是否在集合時,用k個hash函數計算出k個散列值,並查詢數組中對應的比特位,若是全部的比特位都是1,認爲在集合中(k值個數由誤判率決定,誤判率越小則k值越大,誤判率越大則k值越小)
  • 不須要存儲key,節省空間

布隆過濾器代碼實現

  • 代碼實現
    package com.f.fmodules.fuser.bloom;
    
    	import com.google.common.base.Charsets;
    	import com.google.common.hash.BloomFilter;
    	import com.google.common.hash.Funnels;
    
    	import java.util.*;
    
    	public class BloomFilterDemo {
    
    		public static void main(String[] args) {
    			final int count = 500000;
    			List<String> stringList = new ArrayList<>(count);
    			Set<String> stringSet = new HashSet<>();
    			//建立布隆過濾器 初始化過濾器數據
    			BloomFilter<String> bloomString = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),count);
    			for (int i =0;i< count;i++){
    				String id = UUID.randomUUID().toString();
    				stringList.add(id);
    				stringSet.add(id);
    				bloomString.put(id);
    			}
    			int wrong = 0;
    			int right = 0;
    			for (int i =0;i< count; i++) {
    				String checkString = i % 100 == 0 ? stringList.get(i) : UUID.randomUUID().toString();
    				//布隆過濾器 進過hash算法和byte數組 校驗是否存在於集合中
    				if (bloomString.mightContain(checkString)){
    					//校驗是否誤判
    					if (stringSet.contains(checkString)){
    						right++;
    					}else{
    						wrong++;
    					}
    				}
    			}
    			System.out.println("50萬測試數據-->共抵擋: "+(count - wrong - right)+"次非法入侵"+"    誤判"+wrong);
    		}
    	}
  • 運行結果
  • 成功訪問5000是正確答案 50萬對100取模 恰好是5000
    爲何會有14721次誤判呢 我們跟進源碼進行深刻探索
    深刻源碼可發現 誤判率在百分之三的狀況下 有300多萬個byte數組 會進行5次hash算法進行判斷數據是否存在已知數據中
  • 初始化布隆過濾器時設置誤判率爲0.01
    //建立布隆過濾器 初始化過濾器數據
    	BloomFilter<String> bloomString = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),count,0.001);
  • debug深刻源碼

    此時發現誤判率設置爲百分之一的狀況下 byte數組達到七百多萬 而須要進行的hash算法次數達到十次
  • 查看運行結果

    結果可看出 誤判率爲百分之一的狀況下 5000次正確訪問 只有500屢次誤判

思考

  • 算法判斷key在集合中時,有必定的機率key其實不在集合中
  • 並非設置的誤判率越小越好,誤判率越小表明須要進行hash計算次數越多消耗資源越多,應根據實際狀況進行決策
  • k值沒法刪除

總結

  • 我的以爲若使用此過濾器(條件容許的狀況下)可專門用一臺服務區用來初始化集合裏面的值.
相關文章
相關標籤/搜索