Redis面試精講 Day 22:Redis布隆過濾器應用場景

【Redis面試精講 Day 22】Redis布隆過濾器應用場景

在高并發、大數據量的互聯網系統中,如何高效判斷一個元素是否存在于集合中,是緩存設計中的關鍵問題。尤其是在面對緩存穿透——即惡意或無效請求頻繁查詢不存在的數據,導致數據庫壓力劇增——這一經典難題時,傳統方案如緩存空值或黑白名單往往存在內存占用高、維護成本大等問題。

此時,Redis布隆過濾器(Bloom Filter) 成為了最優解之一。作為“Redis面試精講”系列的第22天,本文聚焦【Redis布隆過濾器應用場景】,深入剖析其原理、實現機制與生產實踐,結合Java、Python、Go多語言代碼示例,解析高頻面試題,并提供結構化答題模板,幫助你在中高級后端開發、架構師崗位面試中脫穎而出。

布隆過濾器雖不能100%精確判斷元素是否存在,但以極小的空間代價實現了高效的“可能存在”判斷,是解決緩存穿透、URL去重、用戶推薦去重等場景的利器。掌握其底層邏輯與工程落地方式,已成為大廠面試官考察候選人系統設計能力的重要維度。


一、概念解析:什么是布隆過濾器?

布隆過濾器(Bloom Filter) 是一種基于概率的數據結構,用于快速判斷一個元素是否可能存在于集合中一定不存在。它由 Burton Howard Bloom 在1970年提出,核心思想是使用多個哈希函數將元素映射到位數組中的多個位置。

  • 如果所有對應位都為1 → 元素可能存在
  • 如果任一位為0 → 元素一定不存在

其最大特點是:

  • 空間效率極高:相比HashSet,內存占用可降低90%以上
  • 查詢速度快:O(k),k為哈希函數個數
  • 存在誤判率(False Positive):可能將不存在的元素誤判為存在(但不會漏判)
  • 不支持刪除操作(標準版)

在Redis中,布隆過濾器通常通過 RedisBloom模塊 實現,需提前加載該擴展模塊才能使用相關命令。


二、原理剖析:布隆過濾器如何工作?

1. 核心結構

布隆過濾器由兩部分組成:

  • 一個長度為 m位數組(bit array),初始全為0
  • k 個獨立的哈希函數,每個函數將輸入映射到位數組的某個索引
2. 添加元素流程
  1. 對元素 x 使用 k 個哈希函數計算出 k 個位置
  2. 將位數組中這 k 個位置置為1
3. 查詢元素流程
  1. 對元素 x 使用相同 k 個哈希函數計算位置
  2. 檢查位數組中這些位置是否全為1
  • 是 → “可能存在”
  • 否 → “一定不存在”
4. 誤判率影響因素

誤判率受三個參數影響:

  • n:已插入元素個數
  • m:位數組長度
  • k:哈希函數個數

理想誤判率公式為:
P=(1?e?kn/m)k P = \left(1 - e^{-kn/m}\right)^k P=(1?e?kn/m)k

通常在初始化時指定期望的 nP,RedisBloom會自動計算最優的 mk


三、代碼實現:多語言客戶端操作示例

1. RedisBloom模塊安裝(前提)
# 下載RedisBloom模塊(以Linux為例)
wget https://github.com/RedisBloom/RedisBloom/releases/latest/download/redisbloom.so# 啟動Redis并加載模塊
redis-server --loadmodule ./redisbloom.so

確認模塊加載成功:

redis-cli MODULE LIST

應看到 bf 命令可用。


2. Redis命令操作示例
# 創建布隆過濾器:key=users.filter,預期插入10000條,誤判率0.1%
BF.RESERVE users.filter 0.1 10000# 添加元素
BF.ADD users.filter "user1001"
BF.ADD users.filter "user1002"# 查詢元素
BF.EXISTS users.filter "user1001"  # 返回 1(可能存在)
BF.EXISTS users.filter "user9999"  # 可能返回 1(誤判)或 0(一定不存在)

3. Java實現(Jedis + JRedisBloom)

添加依賴:

<dependency>
<groupId>io.github.hengyunabc</groupId>
<artifactId>jredisbloom</artifactId>
<version>1.0.0</version>
</dependency>

代碼示例:

import redis.clients.jedis.Jedis;
import redis.clients.jedisbloom.BloomFilter;public class BloomFilterExample {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);// 創建布隆過濾器:誤判率0.01,預期元素10000
BloomFilter filter = new BloomFilter(jedis, "user.filter", 0.01, 10000);// 添加用戶ID
filter.add("user1001");
filter.add("user1002");// 檢查是否存在
boolean exists1 = filter.contains("user1001"); // true
boolean exists2 = filter.contains("user9999"); // false 或 true(誤判)System.out.println("user1001 exists: " + exists1);
System.out.println("user9999 exists: " + exists2);jedis.close();
}
}

4. Python實現(pyreBloom)

安裝:

pip install pyreBloom

代碼:

import redis
from pyrebloom import BloomFilter# 連接Redis
client = redis.StrictRedis(host='localhost', port=6379, db=0)# 創建布隆過濾器:10000元素,誤判率0.1%
bf = BloomFilter('user.filter', capacity=10000, error_rate=0.001, conn=client)# 插入數據
bf.add('user1001')
bf.add('user1002')# 查詢
print('user1001 in filter:', 'user1001' in bf)  # True
print('user9999 in filter:', 'user9999' in bf)  # 可能為True(誤判)

5. Go實現(go-redis + redisbloom-go)
package mainimport (
"fmt"
"github.com/go-redis/redis/v8"
"github.com/RedisBloom/redisbloom-go"
"context"
)func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
ctx := context.Background()// 創建布隆過濾器
bf := redisbloom.NewRedisBloom(rdb)
err := bf.Reserve(ctx, "user.filter", 0.01, 10000)
if err != nil && !err.Error().Contains("already exist") {
panic(err)
}// 添加元素
bf.Add(ctx, "user.filter", "user1001")
bf.Add(ctx, "user1002")// 查詢
exists1, _ := bf.Exists(ctx, "user.filter", "user1001")
exists2, _ := bf.Exists(ctx, "user.filter", "user9999")fmt.Printf("user1001 exists: %t\n", exists1)
fmt.Printf("user9999 exists: %t\n", exists2)
}

四、面試題解析:高頻問題深度剖析

1. 布隆過濾器為什么會有誤判?如何降低誤判率?

答題要點:

  • 誤判原因:多個不同元素的哈希值可能映射到相同的位,導致位數組被提前置1
  • 降低方法:
  • 增加位數組長度 m
  • 合理選擇哈希函數個數 k
  • 控制插入元素數量 n 不超過預期
  • 實際中通過 BF.RESERVE 預設容量和誤判率,RedisBloom自動優化參數

加分項:

  • 提到“誤判不可完全避免,但可通過業務兜底(如數據庫查詢)處理”
  • 舉例:誤判率0.1%意味著每1000次查詢可能有1次誤判,可接受

2. 布隆過濾器支持刪除嗎?如果不支持,怎么辦?

答題要點:

  • 標準布隆過濾器不支持刪除,因為多個元素可能共享某些位,直接清零會影響其他元素
  • 解決方案:
  • 使用計數型布隆過濾器(Counting Bloom Filter):用計數器代替bit,支持增減
  • 但RedisBloom默認不開啟,需手動配置
  • 或采用定期重建策略:每天凌晨重建過濾器

代碼示例(開啟計數):

# RedisBloom支持通過參數控制,但需注意內存翻倍
# 實際中較少使用,推薦重建

3. 布隆過濾器和Redis緩存空值相比,有什么優勢?
對比項緩存空值布隆過濾器
內存占用高(每個空Key都存儲)極低(共享位數組)
維護成本高(需設置TTL、清理)低(自動管理)
適用場景少量熱點空Key大規模非法請求過濾
擴展性

結論:布隆過濾器更適合高并發、大規模非法請求過濾場景,如防爬蟲、防刷單。


五、實踐案例:生產環境應用

案例1:電商系統防緩存穿透

背景:用戶頻繁查詢不存在的商品ID(如/product/9999999),導致Redis未命中,直接打到數據庫。

解決方案

  1. 在服務入口層加入布隆過濾器
  2. 查詢前先調用 BF.EXISTS product.filter "9999999"
  3. 若返回0,直接返回404,不查緩存也不查DB
  4. 若返回1,繼續走正常緩存查詢流程

效果

  • 數據庫QPS下降80%
  • 內存占用僅為傳統空值緩存的5%

案例2:新聞推薦去重

背景:用戶已瀏覽過某新聞,不應重復推薦。

方案

  • 為每個用戶創建一個布隆過濾器 user:123:bloom
  • 用戶瀏覽新聞時,將news:456加入過濾器
  • 推薦時先檢查是否已存在,若存在則跳過

優勢

  • 相比Redis Set,內存節省90%
  • 查詢速度快,適合高并發推薦場景

六、技術對比:布隆過濾器 vs 其他去重方案

方案空間效率查詢速度支持刪除誤判率
HashSet (Redis Set)O(1)支持
布隆過濾器極高O(k)不支持有(可控)
布谷鳥過濾器(Cuckoo Filter)O(1)支持有(更低)
數據庫唯一索引O(log n)支持

布谷鳥過濾器是布隆過濾器的升級版,支持刪除且誤判率更低,但RedisBloom也已支持,需權衡復雜度。


七、面試答題模板:結構化回答技巧

當被問及“如何防止緩存穿透”時,可這樣回答:

“我通常采用布隆過濾器作為第一道防線:

  1. 在服務接入層前置布隆過濾器,攔截99%的非法請求;
  2. 使用RedisBloom模塊,預設容量和誤判率,自動優化參數;
  3. 對于通過過濾器的請求,再走緩存 → 數據庫流程;
  4. 同時配合緩存空值作為兜底,防止布隆誤判導致漏過;
  5. 實際項目中,我們用它過濾惡意爬蟲,數據庫壓力下降80%。

相比直接緩存空值,布隆過濾器內存更省、維護更簡單。”


八、總結與預告

核心知識點回顧

  • 布隆過濾器是概率性數據結構,用于判斷元素“可能存在”或“一定不存在”
  • 通過多個哈希函數 + 位數組實現高效查詢
  • 不支持刪除,但可通過計數型或定期重建解決
  • 適用于緩存穿透防護、URL去重、推薦去重等場景
  • Redis通過 RedisBloom模塊 提供原生支持

面試官喜歡的回答要點
? 清晰解釋誤判原理與可接受性
? 能對比不同方案(如空值緩存 vs 布隆)
? 提到RedisBloom模塊和實際命令
? 結合生產案例說明落地效果
? 提出優化建議(如參數調優、定期重建)

下一篇預告:Day 23將深入探討【Redis與數據庫數據一致性保障】,解析雙寫一致性、延遲雙刪、分布式鎖等核心策略,幫助你在高并發場景下設計穩健的數據同步方案,敬請期待!


文章標簽:Redis, 布隆過濾器, 緩存穿透, RedisBloom, 數據結構, 高并發, 面試, Java, Python, Go

文章簡述
本文系統講解Redis布隆過濾器的原理、實現與應用場景,深入剖析其在緩存穿透防護、推薦去重等生產環境中的實戰價值。文章涵蓋RedisBloom模塊使用、多語言(Java/Python/Go)代碼實現、高頻面試題解析,并提供結構化答題模板。通過對比傳統方案,突出布隆過濾器在空間效率與查詢性能上的優勢,幫助開發者掌握這一高階技術,從容應對中高級崗位面試挑戰。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93339.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93339.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93339.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spark Shuffle中的數據結構

文章目錄1.Shuffle中的三種數據結構2.AppendOnlyMap原理2.1 聚合2.2 擴容2.3 排序2.4 為什么是數組&#xff1f;3.ExternalAppendOnlyMap原理3.1 工作原理3.2 AppendOnlyMap大小估計3.2.1 為什么要估計大小&#xff1f;3.2.2 估計大小淺析3.2.2.1 什么時候采樣&#xff1f;3.2.…

告別在線轉換風險:本地運行的PDF轉Word技術評測

Word文檔&#xff08;.docx&#xff09;是可編輯的主流辦公格式&#xff0c;支持靈活修改文字、排版、圖片、表格等。它的體積僅有5.5M&#xff0c;小巧不占空間&#xff0c;且轉換不限文件大小&#xff0c;隨用隨轉&#xff0c;毫無限制。初次使用需完成一次安裝&#xff0c;之…

整體設計 符號學與詮釋學融合的整體設計框架(本篇暫時命名)--PromptPilot (助手)答問之1

說明 本系列篇&#xff08;分多篇&#xff09;是就前面 已經和騰訊元寶就“整體設計”的討論內容 再和 PromptPilot &#xff08;助手&#xff09;的再次溝通。但內容做了部分修正一邊 更準確和完整。摘要&#xff08;CSDN的AI助手提取的&#xff09;符號學與詮釋學融合的整體設…

Font shape `TU/ptm/m/n‘ undefined(Font) using `TU/lmr/m/n‘ instead

一、警告內容 這是 LaTeX 字體選擇機制輸出的信息。我們可以把 TU/ptm/m/n 分解來看&#xff1a; TU → 編碼 (font encoding) TU 表示 Unicode TeX encoding&#xff0c;即新版 XeLaTeX/LuaLaTeX 下的 Unicode 字體編碼。 ptm → 字體族 (family) ptm 代表 Times 字體 (PostS…

拒絕造輪子(C#篇)ZLG CAN卡驅動封裝應用

拒絕造輪子&#xff08;C#篇&#xff09;ZLG CAN卡驅動封裝應用 今天給大家介紹一個封裝完善的CAN卡類。 背景 在面對常規開發場景&#xff0c;開發者對復雜SDK進行封裝和測試。閱讀相關開發資料和理解SDK的DEMO程序。 開篇 如果你也有同樣的煩惱&#xff0c;那就來看看今…

機器學習相關算法:回溯算法 貪心算法 回歸算法(線性回歸) 算法超參數 多項式時間 樸素貝葉斯分類算法

整理了一張“機器學習相關算法與概念速覽表”&#xff0c;既包含定義&#xff0c;也配上了容易記住的例子&#xff0c;讓大家一眼就能抓住它們的特點&#xff1a; &#x1f916; 機器學習與相關算法&概念 名稱定義生動例子典型應用場景回溯算法通過不斷嘗試和回退來尋找問…

vue+微信小程序 五角星

說明&#xff1a;這個是先畫出一個72度菱形&#xff0c;長中長線和短中長線按照一定比例&#xff0c;然后把菱形分層十份&#xff0c;最后再把菱形進行旋轉形成五角星&#xff0c;最后顯示標簽&#xff0c;因為一直對不上所以對標簽做了點操作 <template><view class&…

Prometheus + Grafana 深度玩法:從零到智能化監控體系

0. 寫在前面&#xff1a;為什么你需要“神器”而非“常用命令老楊折騰監控系統可是有年頭了&#xff0c;最早還用過 Cacti、Zabbix&#xff0c;那會兒做個儀表盤都得像雕花一樣慢慢刻。后來 Prometheus 出來之后&#xff0c;我的第一反應是&#xff1a;這玩意兒的時間序列和標簽…

YOLO、DarkNet和深度學習如何讓自動駕駛看得清?

【導讀】 本文提出 DarkNet-YOLO 工業級實踐框架&#xff0c;通過引入 殘差優化結構 與 多尺度特征融合技術&#xff0c;在保持實時檢測精度同時顯著提升復雜場景適應性。 目錄 一、目標檢測的進化之路&#xff1a;從“兩步走”到“一眼定乾坤” YOLO的核心思想&#xff1a…

使用 HTML5 Canvas 打造炫酷的數字時鐘動畫

在 Web 開發中&#xff0c;HTML5 的 canvas 元素為我們帶來了強大的繪圖能力&#xff0c;結合 JavaScript&#xff0c;可以實現各種酷炫的效果。今天&#xff0c;我們將深入剖析一段經典的 彩色數字時鐘動畫 代碼&#xff0c;并理解它是如何通過物理模擬實現數字切換時的炫酷粒…

XCZU6CG-2FFVC900I Xilinx FPGA AMD ZynqUltraScale+ MPSoC

XCZU6CG-2FFVC900I Xilinx FPGA&#xff08; AMD&#xff09;Zynq UltraScale MPSoC 。在處理系統&#xff08;PS&#xff09;方面&#xff0c;XCZU6CG 系列通常集成了 ARM Cortex-A53 應用核與 Cortex-R5 實時核的組合&#xff08;典型為 A53 多核 R5 雙核組合&#xff09;&…

Navicat 詢問 AI | 優化 SQL 查詢

近期&#xff0c;我們發布了 Navicat 17.3 版本。這一版本實現了全方位升級&#xff0c;包括對 AI 功能大升級、支持達夢、金倉、瀚高、支持阿里通義千問等 AI 大模型&#xff0c;支持凝思 OS 以及多項 UI 改進。今天&#xff0c;我們將深入介紹 Navicat AI 功能之“詢問 AI ”…

4.6 Vue 3 中的模板引用 (Template Refs)

在 Vue 3 中&#xff0c;ref 是一個核心的響應式 API&#xff0c;但它在模板中還有另一個非常重要的用途&#xff1a;獲取對 DOM 元素或子組件實例的直接引用。這就是我們所說的“模板引用”。核心概念目的&#xff1a;讓你在父組件中能夠直接訪問并操作特定的 DOM 元素或子組件…

模式匹配自動機全面理論分析

模式匹配是什么 模式匹配是計算機科學中一個基礎且重要的問題&#xff0c;廣泛應用于文本編輯、信息檢索、網絡安全、生物信息學等多個領域。簡單來說&#xff0c;模式匹配就是在一個主文本中查找一個或多個特定模式串的出現位置。隨著計算機處理能力的提升和數據規模的擴大&am…

AI 搜索時代:引領變革,重塑您的 SEO 戰略

隨著谷歌轉向人工智能驅動的答案&#xff0c;使用以關鍵字和反向鏈接為中心的過時和傳統的 SEO 策略不再起到任何作用。 由于 Google AI Overviews 和零點擊搜索的興起&#xff0c;自然點擊量正在下降&#xff0c;用戶無需點擊任何網站即可直接在 Google 的搜索結果頁面上獲得答…

【網站深入seo方法】

目錄 ①對于更成熟的網站&#xff0c;簡單的index.html的入口文件的seo已經無法滿足&#xff0c;需要在商品詳情不同商品被搜索時賦予不同的title和description。 ②通過設置站點所有頁面都新增Canonical標簽&#xff0c;指定規范鏈接地址給谷歌并規避聯盟的重復內容頁面。 ③…

ROS move_base 混合功能導航 RealSense D435i + 3D 點云地圖 + 樓層切換 + 路徑錄制 + 路徑規劃

Mixed-Navigation 這個博客也是記錄我們的一個開源項目&#xff0c;其作用是混合功能導航。由于現有的 Fast-Lio-Localization 只實現了定位功能&#xff0c;但對于路徑規劃和樓層切換沒有具體實現&#xff0c;因此我們開出了這個倉庫作為參考。該倉庫的核心功能如下&#xff…

初識c語言————宏定義和調用

目錄&#xff1a;一.不帶參數的宏二.帶參數宏一.不帶參數的宏不帶參數的宏是指用#define指令定義的簡單文本替換規則&#xff0c;它沒有參數列表&#xff0c;直接替換標識符為相應的文本其一般形式為&#xff1a;#define 宏名 文本例如&#xff1a;#define pi 3.14這個代…

數據結構:滿二叉樹 (Full Binary Tree) 和 完全二叉樹 (Complete Binary Tree)

目錄 重要的術語澄清 完美二叉樹 (Perfect Binary Tree) 完全二叉樹 (Complete Binary Tree) 大比拼 (Comparison) 相互關系的第一性推導 我們來深入探討兩種在算法中非常重要的、具有特定“形狀”的二叉樹&#xff1a;滿二叉樹 (Full Binary Tree) 和 完全二叉樹 (Compl…

OpenJDK 17的C1和C2編譯器實現中,方法返回前插入安全點(Safepoint Poll)的機制

OpenJDK 17 JIT編譯器堆棧分析-CSDN博客 在OpenJDK 17的C1和C2編譯器實現中&#xff0c;方法返回前插入安全點&#xff08;Safepoint Poll&#xff09;的機制主要涉及以下關鍵步驟&#xff0c;結合源代碼進行分析&#xff1a; 1. 安全點輪詢樁&#xff08;Safepoint Poll Stu…