一文徹底弄清Redis的布隆過濾器

lgx211發表於2024-10-21

布隆過濾器(Bloom Filter)是一種空間效率極高的資料結構,用於快速判斷一個元素是否在集合中。它能夠節省大量記憶體,但它有一個特點:可能存在誤判,即可能會認為某個元素存在於集合中,但實際上不存在;而對於不存在的元素,它保證一定不會誤判。布隆過濾器適合在對儲存空間要求極為嚴格,同時能接受少量誤判的應用場景中使用。

1. 布隆過濾器的工作原理

布隆過濾器的核心思想是使用多個雜湊函式(Hash Functions)和一個位陣列(Bit Array)。其操作過程如下:

1.1 插入元素

  • 當插入一個元素時,布隆過濾器會使用多個不同的雜湊函式對該元素進行雜湊計算,得到多個雜湊值(位置索引),並將這些雜湊值對應的位陣列位置設定為 1
  • 例如,一個元素經過 3 個雜湊函式後,得到了 3 個不同的位置,布隆過濾器就在這 3 個位置上將位陣列的值設為 1

1.2 查詢元素

  • 查詢某個元素時,布隆過濾器會使用相同的雜湊函式對該元素進行雜湊計算,得到多個位置。如果所有這些位置的位都為 1,則布隆過濾器認為這個元素可能存在;如果任意一個位置的位為 0,則可以確定這個元素一定不存在

1.3 特點

  • 可能存在誤判:布隆過濾器有可能出現誤判,查詢一個不存在的元素時,有小機率會因為位陣列中的某些位被其他元素設為 1,而誤認為這個元素存在。
  • 不會漏判:如果某個元素不存在,布隆過濾器一定不會誤判其存在,即布隆過濾器查詢某個元素是否存在時,若判斷不存在,結果是可靠的。

2. 布隆過濾器的組成部分

2.1 位陣列(Bit Array)

位陣列是布隆過濾器的核心資料結構。它是一個長度為 m 的陣列,每個位置上只能儲存 01。初始時,位陣列中所有位置的值都為 0。在插入元素時,雜湊函式根據元素值生成若干個位置索引,並將這些索引對應的位設為 1

2.2 雜湊函式(Hash Functions)

布隆過濾器使用多個雜湊函式(通常是獨立的雜湊函式)來對元素進行雜湊操作。每個雜湊函式會生成一個不同的位陣列索引,用於確定元素的儲存位置。

  • 選擇的雜湊函式應當具有較好的均勻性,確保雜湊值能夠均勻分佈在位陣列上,減少衝突。

2.3 雜湊函式的數量(k 值)

k 表示用於每個元素的雜湊函式的個數。雜湊函式數量越多,誤判的機率越低,但查詢和插入的複雜度會增加。因此,k 的數量一般選擇一個合適的中間值,以在查詢效能和誤判率之間取得平衡。

2.4 位陣列的長度(m 值)

m 是位陣列的長度,位陣列越長,誤判率越低,但需要佔用的記憶體也更多。因此,位陣列的長度應該根據實際的業務需求和記憶體開銷進行權衡設計。

3. 布隆過濾器的誤判率

布隆過濾器的誤判率是指在查詢時,布隆過濾器錯誤地認為一個不存在的元素存在於集合中的機率。誤判率隨著集合中插入的元素數量的增加而增加,主要受到以下幾個因素的影響:

  • 位陣列長度(m):位陣列越長,誤判率越低。
  • 雜湊函式數量(k):雜湊函式數量適中時誤判率最低,但數量過多會使得誤判率增加。
  • 元素數量(n):插入的元素越多,誤判率越高,因為位陣列中被設定為 1 的位越來越多,雜湊函式的碰撞機會增大。

布隆過濾器的誤判率計算公式如下: p=(1−e−k⋅nm)kp = \left( 1 - e^{- \frac{k \cdot n}{m}} \right)^kp=(1−e−mk⋅n)k

  • p 是誤判率;
  • k 是雜湊函式的數量;
  • n 是插入的元素數量;
  • m 是位陣列的長度。

4. 布隆過濾器的優缺點

4.1 優點

  • 高效的空間利用率:布隆過濾器可以用較小的空間儲存大量資料,尤其在元素數量很大時,它可以顯著節省記憶體。
  • 查詢和插入操作的時間複雜度很低:無論插入還是查詢,布隆過濾器的時間複雜度都是 O(k),即與雜湊函式的數量成線性關係,速度非常快。
  • 適合大規模資料過濾:對於海量資料的存在性判斷,布隆過濾器非常高效,適合在需要快速判斷某個元素是否存在的場景中使用。

4.2 缺點

  • 存在誤判:布隆過濾器可能會誤判一個元素存在,即判斷結果可能為“假陽性”(False Positive),這意味著雖然布隆過濾器認為某個元素存在,但實際上它並不存在。布隆過濾器不適合用於需要精準判斷的場景。
  • 無法刪除元素:布隆過濾器無法直接刪除元素,因為雜湊函式將多個元素對映到同一位陣列位置,刪除某個元素可能會導致其他元素的雜湊結果失效。雖然有計數布隆過濾器(Counting Bloom Filter)可以支援刪除操作,但其實現更加複雜。

5. 布隆過濾器的典型應用場景

5.1 快取穿透防護

  • 布隆過濾器最常見的應用之一就是防止

    快取穿透

    。在 Redis 快取場景中,使用者請求的資料可能在快取和資料庫中都不存在,如果不加以防護,這些請求會直接打到資料庫。透過布隆過濾器,可以在請求前判斷元素是否可能存在於資料庫中,從而減少無效的資料庫查詢。

    • 場景: 一個電商系統中,使用者可能會頻繁查詢一些並不存在的商品 ID。布隆過濾器可以用來儲存所有合法商品 ID,在查詢前進行判斷,如果布隆過濾器中不存在,則可以直接返回空結果,而不必查詢資料庫和快取。

5.2 垃圾郵件過濾

  • 布隆過濾器可以用於垃圾郵件系統,用來快速判斷某個電子郵件地址或 IP 是否在黑名單列表中。由於布隆過濾器的高效性,可以極大提高垃圾郵件檢測的速度,並節省記憶體資源。

5.3 大資料去重

  • 在大規模資料處理場景中,布隆過濾器可以用來檢測某個元素是否已經出現過,從而實現去重操作。它特別適用於對記憶體要求嚴格的系統中,比如分散式爬蟲系統中需要去重的 URL 處理。

5.4 資料庫和儲存系統

  • 布隆過濾器被廣泛應用於資料庫和儲存系統中,用於減少不必要的磁碟 I/O 操作。例如:
    • HBase 使用布隆過濾器來加快查詢速度,避免不必要的磁碟讀取。
    • Cassandra 使用布隆過濾器來判斷某個 SSTable 是否包含某個鍵,從而減少磁碟掃描次數。

6. 布隆過濾器的擴充套件

6.1 計數布隆過濾器(Counting Bloom Filter)

計數布隆過濾器是一種支援刪除操作的布隆過濾器。與標準布隆過濾器不同的是,計數布隆過濾器的位陣列中的每個位置不再是二進位制的 01,而是一個計數器。當插入一個元素時,多個雜湊函式對應的位上的計數器增加;當刪除一個元素時,計數器相應減少。

計數布隆過濾器的缺點是需要更多的儲存空間(因為每個位置是一個計數器),但它允許刪除元素,這使得它適用於動態更新的場景。

6.2 分散式布隆過濾器

在大規模分散式系統中,布隆過濾器可以擴充套件為分散式布隆過濾器,即將位陣列分佈在多個節點上,並且每個節點負責一部分位陣列的儲存和雜湊計算。這樣可以提高系統的可擴充套件性,適應更大規模的資料集。

總結

布隆過濾器是一種空間效率極高的資料結構,適用於需要快速判斷某個元素是否存在的場景,尤其適用於防止快取穿透、垃圾郵件過濾、大資料去重等場景。雖然它存在一定的誤判率,但其出色的空間效率和查詢效能使其成為許多大規模應用中的重要工具。

相關文章