自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

牛哄哄的布隆過濾器,有什么用?

開發(fā) 架構(gòu) 開發(fā)工具
日常開發(fā)中,大家經(jīng)常使用緩存,但是你知道大型的互聯(lián)網(wǎng)公司面對(duì)高并發(fā)流量,要注意緩存穿透問題嗎?

[[421357]]

圖片來自 包圖網(wǎng)

本文會(huì)介紹布隆過濾器,空間換時(shí)間,以較低的內(nèi)存空間、高效解決這個(gè)問題。

性能不夠,緩存來湊

現(xiàn)在的年輕人都喜歡網(wǎng)購,沒事就逛逛淘寶,剁剁手,買些自己喜歡的東西,釋放下工作壓力。

地址:

  1. https://detail.tmall.com/item.htm?id=628993216729 

上圖是一個(gè)天貓 iPhone12 的商品詳情頁,id 表示商品的編號(hào)。

我們都知道淘寶的訪問量是非常高的,為了提升系統(tǒng)的吞吐量,做了很多性能優(yōu)化,其中非常重要一點(diǎn)是將信息異構(gòu)到緩存中。

有句話說的好:性能不夠,緩存來湊。但是,使用緩存時(shí),我們要關(guān)注一個(gè)重要問題,如果緩存沒有命中怎么辦?

[[421358]]

緩存沒有命中,怎么辦?

如上圖:

  • 我們先查詢緩存,判斷緩存中是否有數(shù)據(jù)
  • 如果有數(shù)據(jù),直接返回
  • 如果緩存為空,我們需要再查一次數(shù)據(jù)庫,并將數(shù)據(jù)格式異構(gòu)化,然后預(yù)熱到緩沖中,然后將結(jié)果返回

注意:步驟③存在風(fēng)險(xiǎn)漏洞,如果緩存中數(shù)據(jù)不存在,壓力會(huì)轉(zhuǎn)嫁給數(shù)據(jù)庫。假如被競(jìng)爭(zhēng)對(duì)手利用,搞無效請(qǐng)求流量攻擊,瞬間大量請(qǐng)求打到數(shù)據(jù)庫中,對(duì)系統(tǒng)性能產(chǎn)生很大影響,很容易把數(shù)據(jù)庫打掛,這種現(xiàn)象稱為緩存穿透。

那么如何處理緩存穿透?

我們的思路是,緩存中能不能判斷這個(gè)數(shù)據(jù)庫值的存在性,如果真的不存在,直接返回,也避免一次數(shù)據(jù)庫查詢。

由于不存在是個(gè)無限邊界,所以,我們采用反向策略,將存在的值建立一個(gè)高效的檢索。每次緩存取值時(shí),先走一次判空檢索。

簡(jiǎn)單歸納下,這個(gè)框架的要求:

  • 快速檢索
  • 內(nèi)存空間要非常小

經(jīng)調(diào)研,我們發(fā)現(xiàn)布隆過濾器具備以上兩個(gè)條件。

什么是布隆過濾器?

布隆過濾器(Bloom Filter)是 1970 年由布隆提出的。它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。

布隆過濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中:

優(yōu)點(diǎn):空間效率和查詢時(shí)間都遠(yuǎn)遠(yuǎn)超過一般的算法。

缺點(diǎn):有一定的誤識(shí)別率,刪除困難。

布隆過濾器如何構(gòu)建?

布隆過濾器本質(zhì)上是一個(gè) n 位的二進(jìn)制數(shù)組,用 0 和 1 表示。假如我們以商品為例,有三件商品,商品編碼分別為,id1、id2、id3。

①首先,對(duì) id1,進(jìn)行三次哈希,并確定其在二進(jìn)制數(shù)組中的位置。

三次哈希,對(duì)應(yīng)的二進(jìn)制數(shù)組下標(biāo)分別是 2、5、8,將原始數(shù)據(jù)從 0 變?yōu)?1。

②對(duì) id2,進(jìn)行三次哈希,并確定其在二進(jìn)制數(shù)組中的位置。

三次哈希,對(duì)應(yīng)的二進(jìn)制數(shù)組下標(biāo)分別是 2、7、98,將原始數(shù)據(jù)從 0 變?yōu)?1。

下標(biāo) 2,之前已經(jīng)被操作設(shè)置成 1,則本次認(rèn)為是哈希沖突,不需要改動(dòng)。

Hash 規(guī)則:如果在 Hash 后,原始位它是 0 的話,將其從 0 變?yōu)?1;如果本身這一位就是 1 的話,則保持不變。

布隆過濾器如何使用?

如下圖:

跟初始化的過程有點(diǎn)類似,當(dāng)查詢一件商品的緩存信息時(shí),我們首先要判斷這件商品是否存在:

  • 通過三個(gè)哈希函數(shù)對(duì)商品 id 計(jì)算哈希值
  • 然后,在布隆數(shù)組中查找訪問對(duì)應(yīng)的位值,0 或 1
  • 判斷,三個(gè)值中,只要有一個(gè)不是 1,那么我們認(rèn)為數(shù)據(jù)是不存在的。

注意:布隆過濾器只能精確判斷數(shù)據(jù)不存在情況,對(duì)于存在我們只能說是可能,因?yàn)榇嬖?Hash 沖突情況,當(dāng)然這個(gè)概率非常低。

如何減少布隆過濾器的誤判?

①增加二進(jìn)制位數(shù)組的長(zhǎng)度。這樣經(jīng)過 hash 后數(shù)據(jù)會(huì)更加的離散化,出現(xiàn)沖突的概率會(huì)大大降低。

②增加 Hash 的次數(shù),變相的增加數(shù)據(jù)特征,特征越多,沖突的概率越小。

布隆過濾器會(huì)不會(huì)很費(fèi)內(nèi)存?

帶著疑問,我們來做個(gè)實(shí)驗(yàn):假設(shè)有 1 千萬個(gè)數(shù)據(jù),我們需要記錄其是否存在。存在的話標(biāo)記 1,不存在標(biāo)記為 0。技術(shù)選型,框架采用 Redis 的 BitMap 存儲(chǔ)。

數(shù)據(jù)初始化預(yù)熱代碼:

  1. redisTemplate.executePipelined(new RedisCallback<Long>() { 
  2.     @Nullable 
  3.     @Override 
  4.     public Long doInRedis(RedisConnection connection) throws DataAccessException { 
  5.         connection.openPipeline(); 
  6.         for (int offset = 10000000; offset >= 0; offset--) { 
  7.             boolean value = offset % 2 == 0 ? true : false
  8.             connection.setBit("bloom-filter-data-1".getBytes(), offset, value); 
  9.         } 
  10.         connection.closePipeline(); 
  11.         return null
  12.     } 
  13. }); 
  14. System.out.println("數(shù)據(jù)預(yù)熱完成"); 

性能有點(diǎn)慢,我們也可以采用分組形式,10000 個(gè)數(shù)一組,多批次提交。

數(shù)據(jù)上傳完了后,大小 1.19M,跟我們?cè)O(shè)想的一樣。

計(jì)算公式:10000000/8/1024/1024=1.19M

Java 應(yīng)用中,如何使用布隆過濾器?

Java 語言的生態(tài)非常繁榮,提供了很多開箱即用的開源框架供我們使用。布隆過濾器也不例外,Java 中提供了一個(gè) Redisson 的組件,它內(nèi)置了布隆過濾器。

首先引入依賴包:

  1. <dependency> 
  2.     <groupId>org.redisson</groupId> 
  3.     <artifactId>redisson</artifactId> 
  4.     <version>3.11.1</version> 
  5. </dependency> 

代碼示例:

  1. /** 
  2.  * @author  
  3.  */ 
  4. @Test 
  5. public void test5() { 
  6.     Config config = new Config(); 
  7.     config.useSingleServer().setAddress("redis://172.16.67.37:6379"); 
  8.     RedissonClient cient = Redisson.create(config); 
  9.     RBloomFilter<String> bloomFilter = cient.getBloomFilter("test5-bloom-filter"); 
  10.     // 初始化布隆過濾器,數(shù)組長(zhǎng)度100W,誤判率 1% 
  11.     bloomFilter.tryInit(1000000L, 0.01); 
  12.     // 添加數(shù)據(jù) 
  13.     bloomFilter.add("Tom哥"); 
  14.     // 判斷是否存在 
  15.     System.out.println(bloomFilter.contains("微觀技術(shù)")); 
  16.     System.out.println(bloomFilter.contains("Tom哥")); 

運(yùn)行結(jié)果:

  1. false   // 肯定不存在 
  2. true    // 可能存在,有1%的誤判率 

注意:誤判率設(shè)置過小,會(huì)產(chǎn)生更多次的 Hash 操作,降低系統(tǒng)的性能。通常我們的建議值是 1%。

布隆過濾器二進(jìn)制數(shù)組,如何處理刪除?

初始化后的布隆過濾器,可以直接拿來使用了。但是如果原始數(shù)據(jù)刪除了怎么辦?布隆過濾器二進(jìn)制數(shù)組如何維護(hù)?

直接刪除不行嗎?還真不行!因?yàn)檫@里面有 Hash 沖突的可能,會(huì)導(dǎo)致誤刪。

怎么辦?

  • 方案 1:開發(fā)定時(shí)任務(wù),每隔幾個(gè)小時(shí),自動(dòng)創(chuàng)建一個(gè)新的布隆過濾器數(shù)組,替換老的,有點(diǎn) CopyOnWriteArrayList 的味道。
  • 方案 2:布隆過濾器增加一個(gè)等長(zhǎng)的數(shù)組,存儲(chǔ)計(jì)數(shù)器,主要解決沖突問題,每次刪除時(shí)對(duì)應(yīng)的計(jì)數(shù)器減一,如果結(jié)果為 0,更新主數(shù)組的二進(jìn)制值為 0。

布隆過濾器的應(yīng)用場(chǎng)景

如下:

本文重點(diǎn)介紹的,解決緩存穿透。

網(wǎng)頁爬蟲對(duì) URL 的去重,避免爬取相同的 URL 地址。

反垃圾郵件,從數(shù)十億個(gè)垃圾郵件列表中判斷某郵箱是否垃圾郵箱。

作者:Tom哥

編輯:陶家龍

出處:轉(zhuǎn)載自公眾號(hào)微觀技術(shù)(ID:weiguanjishu)

 

責(zé)任編輯:武曉燕 來源: 微觀技術(shù)
相關(guān)推薦

2024-01-05 09:04:35

隆過濾器數(shù)據(jù)結(jié)構(gòu)哈希函數(shù)

2024-09-18 10:08:37

2024-03-15 11:21:22

布隆過濾器數(shù)據(jù)庫數(shù)據(jù)

2023-01-31 08:19:53

二進(jìn)制元素數(shù)量

2025-04-30 08:47:41

2024-11-04 08:45:48

布隆過濾器元數(shù)據(jù)指紋值

2025-02-08 17:30:00

布隆過濾器數(shù)據(jù)結(jié)構(gòu)

2020-10-29 07:16:26

布隆過濾器場(chǎng)景

2019-03-22 15:15:25

Redis緩存擊穿雪崩效應(yīng)

2022-03-21 08:31:07

布隆過濾器Redis過濾器原理

2025-01-23 00:00:00

Java布隆過濾器

2025-01-22 00:00:00

布隆過濾器二進(jìn)制

2024-09-25 17:44:08

2024-10-09 15:54:38

布隆過濾器函數(shù)

2021-03-06 14:41:07

布隆過濾器算法

2023-07-06 10:15:38

布隆過濾器優(yōu)化

2023-04-26 08:32:45

Redis布隆過濾器

2019-10-14 10:29:42

Java消息隊(duì)列

2020-08-28 13:02:17

布隆過濾器算法

2009-07-08 15:30:56

Servlet過濾器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)