Redis的多并發實際業務場景下的使用分析:布隆過濾器

文章目錄

  • 前言
  • 什么是布隆過濾器
  • 項目中引入布隆過濾器
  • 與緩存結合的最佳實踐
  • 場景:高并發用戶訪問商品詳情頁(防止緩存穿透)
  • 總結:

前言

okok 我們已經學完了 所有的redis中的常用的數據結構 下面就是進階
我會用一系列的例子 去講解 如何使用這些數據結構 以及 如何結合到我們的實際業務代碼中去

本文將會介紹布隆過濾器 以及結合緩存的最佳實踐

什么是布隆過濾器

Bloom過濾器是一種空間高效的概率性數據結構,用于快速判斷一個元素是否可能存在于一個集合中。

基本組成:

位數組(Bit Array): 長度為m的二進制數組,初始全為0
哈希函數集合: k個獨立的哈希函數 h?, h?, …, h?
元素集合: 需要存儲的數據集合

工作流程分析:

插入操作 (Add)

  1. 對元素x計算k個哈希值: h?(x), h?(x), …, h?(x)
  2. 將位數組中對應位置設為1:
    bit[h?(x) % m] = 1
    bit[h?(x) % m] = 1
    bit[h?(x) % m] = 1 …

查詢操作 (Query)

  1. 對元素x計算k個哈希值: h?(x), h?(x), …, h?(x)
  2. 檢查位數組中對應位置: if bit[h?(x) % m] == 1 AND
    bit[h?(x) % m] == 1 AND
    … AND
    bit[h?(x) % m] == 1:
    return “可能存在” else:
    return “一定不存在”

怎么簡單去理解

就是有 n個 Hash表 每次插入數據 首先hash(數據) 到這 N 個 hash表 每個位置設置為1
然后查詢的時候
再次使用相同的hash函數去hash(數據) 到這 N 個 hash表 檢查每個位置是否為1
若為1 則可能存在通過校驗 (疑問 為什么是可能存在呢?)
若存在某一位為0 則一定不存在 (疑問 為什么是一定不存在呢?)

怎么理解:可能存在

因為存在hash沖突啊 還有可能另外的數據也把當前位置 修改成了1 所以是可能而不是一定

怎么理解:一定不存在
你想想 當前受檢的hash位置 都是0 說明根本就沒有插入過這個數據 如果插入過 則一定會把這一位 置為1 但是為0 說明這個元素沒有插入過當前的布隆過濾器

項目中引入布隆過濾器

依賴:

        <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.50.0</version></dependency>

配置類:

@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();// 如果你是單機模式config.useSingleServer().setAddress("redis://127.0.0.1:6379");return Redisson.create(config);}
}
@Service
@RequiredArgsConstructor
public class RedisBloomFilterService {private final RedissonClient redissonClient;public void initBloomFilter(String name, long expectedInsertions, double falseProbability) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(name);// 初始化:預估元素數量 + 期望誤判率(如 0.01)bloomFilter.tryInit(expectedInsertions, falseProbability);}public void add(String name, String value) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(name);bloomFilter.add(value);}public boolean mightContain(String name, String value) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(name);return bloomFilter.contains(value);}
}

測試類

@SpringBootTest
class RedisBloomFilterServiceTest {@Autowiredprivate RedisBloomFilterService bloomFilterService;@Testvoid testBloomFilter() {String filterName = "user:bloom";// 初始化:10 萬數據,誤判率 1%bloomFilterService.initBloomFilter(filterName, 100_000, 0.01);bloomFilterService.add(filterName, "user_1001");bloomFilterService.add(filterName, "user_1002");assert bloomFilterService.mightContain(filterName, "user_1001"); // trueassert !bloomFilterService.mightContain(filterName, "user_9999"); // very likely false}
}

與緩存結合的最佳實踐

三級防護體系
請求 → Bloom過濾器 → 本地緩存 → Redis緩存 → 數據庫↓              ↓           ↓            ↓攔截99%無效請求   熱點數據    分布式緩存    最終數據源
@Service
public class MultiLevelCacheService {private BloomFilter<String> bloomFilter;      // L0: 布隆過濾器private Cache<String, Object> localCache;     // L1: 本地緩存private RedisTemplate redisTemplate;          // L2: Redis緩存private Database database;                    // L3: 數據庫public Object getData(String key) {// L0: Bloom過濾器檢查if (!bloomFilter.mightContain(key)) {return null; // 一定不存在}// L1: 本地緩存檢查Object data = localCache.getIfPresent(key);if (data != null) {return data;}// L2: Redis緩存檢查data = redisTemplate.opsForValue().get(key);if (data != null) {localCache.put(key, data); // 回填本地緩存return data;}// L3: 數據庫查詢data = database.findById(key);if (data != null) {redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(30));localCache.put(key, data);} else {// 設置空值緩存,防止緩存穿透redisTemplate.opsForValue().set(key, "NULL", Duration.ofMinutes(5));}return data;}
}

場景:高并發用戶訪問商品詳情頁(防止緩存穿透)

用戶通過 /product/{id} 請求商品詳情;

正常流程:Redis 緩存命中 → 返回數據;

若 Redis 未命中,就查 DB → 然后寫入 Redis;

問題:惡意請求 / 錯誤 id 請求不斷打穿緩存,導致 DB 被打爆,這就是「緩存穿透」。

如何解決這個問題 需要使用布隆過濾器

  1. 用戶請求商品 /product/99999
  2. 系統先檢查 BloomFilter.contains(“99999”): → false → 直接拒絕,無需查緩存/數據庫 → true → 正常查 Redis 緩存,未命中則查數據庫

loomFilter 初始化(商品上線時構建)

@PostConstruct
public void initBloomFilter() {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("bloom:product");bloomFilter.tryInit(1_000_000L, 0.01); // 容量:100w,誤判率:1%// 假設所有商品ID:1~1000000for (int i = 1; i <= 1000000; i++) {bloomFilter.add(String.valueOf(i));}
}

Controller 攔截請求:

@GetMapping("/product/{id}")
public ResponseEntity<?> getProduct(@PathVariable String id) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("bloom:product");if (!bloomFilter.contains(id)) {return ResponseEntity.status(HttpStatus.NOT_FOUND).body("非法商品ID,拒絕訪問");}// 查詢緩存String redisKey = "product:" + id;Object product = redisTemplate.opsForValue().get(redisKey);if (product != null) return ResponseEntity.ok(product);// 查詢數據庫(模擬)Product result = productService.queryById(id);if (result != null) {redisTemplate.opsForValue().set(redisKey, result, Duration.ofMinutes(30));return ResponseEntity.ok(result);} else {// 緩存空對象防止緩存穿透redisTemplate.opsForValue().set(redisKey, "NULL", Duration.ofMinutes(10));return ResponseEntity.status(HttpStatus.NOT_FOUND).body("商品不存在");}
}

測試代碼

@Test
public void testBloomFilterConcurrency() throws InterruptedException {ExecutorService executor = Executors.newFixedThreadPool(20);for (int i = 0; i < 1000; i++) {final int id = i;executor.submit(() -> {String fakeId = String.valueOf(id);boolean mayExist = redissonClient.getBloomFilter("bloom:product").contains(fakeId);if (mayExist) {System.out.println("合法ID:" + fakeId + " → 繼續查緩存/DB");} else {System.out.println("非法ID:" + fakeId + " → 攔截");}});}executor.shutdown();executor.awaitTermination(1, TimeUnit.MINUTES);
}

總結:

布隆過濾器 快速判斷一個元素是否可能存在于一個集合中

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

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

相關文章

【AI】人工智能領域關鍵術語全解析

一、前言 人工智能&#xff08;AI&#xff09;作為當今最熱門的技術領域之一&#xff0c;正在深刻改變著我們的生活和工作方式。然而&#xff0c;對于初學者或非技術背景的人士來說&#xff0c;理解AI領域的專業術語可能是一項挑戰。本文旨在全面解析人工智能領域的關鍵術語&a…

【Linux基礎知識系列】第四十三篇 - 基礎正則表達式與 grep/sed

在Linux系統中&#xff0c;正則表達式是一種強大的文本處理工具&#xff0c;廣泛用于文本搜索、替換和批量處理。通過掌握基礎正則表達式的語法&#xff0c;結合grep和sed命令&#xff0c;用戶可以高效地完成復雜的文本處理任務。無論是數據分析師、軟件開發者還是系統管理員&a…

SIMATIC S7-1200的以太網通信能力:協議與資源詳細解析

SIMATIC S7-1200的以太網通信能力&#xff1a;協議與資源解析 在工業自動化領域&#xff0c;PLC的通信能力往往直接影響著整個控制系統的靈活性與高效性。西門子SIMATIC S7-1200系列PLC作為一款廣泛應用的中小型控制器&#xff0c;其強大的以太網通信功能是其核心優勢之一。本文…

什么是高防 IP?從技術原理到實戰部署的深度解析

目錄 前言 一、高防 IP 的定義與核心價值 二、高防 IP 的技術原理與架構 2.1 流量牽引技術 2.2 流量清洗引擎 2.3 回源機制 三、高防 IP 的核心防護技術詳解 3.1 DDoS 攻擊防御技術 3.2 高防 IP 的彈性帶寬設計 四、實戰&#xff1a;基于 Linux 的高防 IP 環境配置 …

NW710NW713美光固態閃存NW719NW720

美光NW系列固態閃存深度解析&#xff1a;技術、性能與市場洞察一、技術架構與核心創新美光NW系列固態閃存&#xff08;包括NW710、NW713、NW719、NW720&#xff09;的技術根基源于其先進的G9 NAND架構。該架構通過5納米制程工藝和多層3D堆疊技術&#xff0c;在單位面積內實現了…

JVM匯總

1.什么是JVM&#xff1f;Java虛擬機&#xff0c;Java具有自動內存管理等一系列特性&#xff0c;為實現Java跨平臺&#xff0c;一次編譯處處執行。2.JVM結構圖3.類加載器-入口加載class文件&#xff0c;將類信息存放到運行時數據區的方法區內存空間中通過魔數和文件格式來判斷是…

2024.09.20 leetcode刷題記錄

# 前言 昨天發布了第一遍博客&#xff0c;感覺很好&#xff0c;趁著我現在還是很感興趣就多發幾遍&#xff0c;希望能堅持下去&#xff0c;在這里記錄下自己學習成長的經歷。 今天是周五&#xff0c;下周一就又要去實習啦&#xff0c;距離上一段實習剛結束一個月&#xff0c;之…

SQLite3 中列(變量)的特殊屬性

在 SQLite3 中&#xff0c;列的特殊屬性通常通過約束&#xff08;Constraints&#xff09;和數據類型修飾符來定義。這些屬性可以在創建表時指定&#xff0c;用于限制數據的完整性或定義特殊行為。以下是 SQLite3 支持的主要特殊屬性及其說明&#xff1a; 1. 主鍵約束&#xff…

Datawhale AI 夏令營:用戶洞察挑戰賽 Notebook(2)

針對文本聚類優化 優化TF-IDF特征工程# 調整ngram_range&#xff1a;設置為(1, 2)&#xff0c;捕捉單字和雙字詞&#xff08;如“不錯”“不滿意”&#xff09;。 # 限制特征數量&#xff1a;通過max_features5000保留高信息密度特征&#xff0c;降低維度。 # 過濾低頻/高頻詞&…

【博主親測可用】PS2025最新版:Adobe Photoshop 2025 v26.8.1 激活版(附安裝教程)

軟件簡介 Adobe Photoshop 2025是Adobe公司開發的一款圖像處理軟件。作為行業標準的數字圖像編輯工具&#xff0c;其核心定位是創意設計、后期攝影、3D建模和AI驅動創作&#xff0c;適用于專業設計師、攝影師、插畫家和多媒體創作者。界面設計簡單直觀&#xff0c;易于操作&…

unity A星尋路

算法 fCost gCost hCost gCost 是當前節點到移動起始點的消耗&#xff0c;hCost是當前節點到終點的消耗 網格為變成為1的矩形&#xff0c;左右相鄰的兩個網格直接的gCost為1&#xff0c;斜對角相鄰的兩個網格的gCost為1.4 hCost 當前網格到終點網格的 水平距離 垂直距離 比如…

十一 Javascript的按值傳遞

你將知道&#xff1a;“傳遞” 值是什么意思什么是按值傳遞傳遞物品JavaScript 中沒有傳遞引用&#xff01;介紹當需要在 JavaScript 中分配或簡單地將一個值傳遞給其他標識符時&#xff0c;我們就會看到通常所說的 按值傳遞 。嚴格來說&#xff0c;JavaScript 中傳遞值的方式只…

SpringBoot ThreadLocal 全局動態變量設置

需求說明&#xff1a; 現有一個游戲后臺管理系統&#xff0c;該系統可管理多個大區的數據&#xff0c;但是需要使用大區id實現數據隔離&#xff0c;并且提供了大區選擇功能&#xff0c;先擇大區后展示對應的數據。需要實現一下幾點&#xff1a; 1.前端請求時&#xff0c;area_i…

如何解決pip安裝報錯ModuleNotFoundError: No module named ‘logging’問題

【Python系列Bug修復PyCharm控制臺pip install報錯】如何解決pip安裝報錯ModuleNotFoundError: No module named ‘logging’問題 摘要&#xff1a; 在使用 PyCharm 2025 控制臺通過 pip install 安裝第三方庫時&#xff0c;常會遇到諸如 ModuleNotFoundError: No module name…

打破技術債困境:從“保持現狀”到成為變革的推動者

相信許多在科技行業的同行都面臨過類似的挑戰&#xff1a;明知系統存在“技術債”&#xff0c;卻因為溝通成本、團隊壓力和短期KPI等原因&#xff0c;難以推動改進&#xff0c;最終陷入“想做卻不敢做”的矛盾心態。這不僅影響個人心情&#xff0c;更重要的是&#xff0c;它像一…

Spring Boot 整合 RabbitMQ

Spring Boot 整合 RabbitMQ 一、概述&#xff1a;RabbitMQ 是什么&#xff1f; 你可以把 RabbitMQ 想象成一個「快遞中轉站」。 比如你在網上買了一本書&#xff0c;賣家&#xff08;生產者&#xff09;把包裹&#xff08;消息&#xff09;交給快遞站&#xff08;RabbitMQ&…

Unity Demo-3DFarm詳解-其一

我們來拆解一個種田游戲&#xff0c;這個游戲種類內部的功能還是比較模板化的&#xff0c;我們來一點點說。我們大體上分為這么幾個部分&#xff1a;農場運營玩法角色與玩家互動物品與背包存檔和進度管理用戶界面系統農場運營可以大體上分為&#xff1a;種植系統&#xff1a;支…

esp8266驅動下載

問題描述&#xff1a;esp8266插上電腦&#xff0c;設備管理器無法識別&#xff0c;顯示為USB serial&#xff08;黃色感嘆號&#xff09; 首先確認你的esp8266是不是 CH340 系列的 USB 轉串口芯片 CH340驅動下載地址

大語言模型的極限:知識、推理與創造力的邊界探析

大語言模型的極限&#xff1a;知識、推理與創造力的邊界探析 人工智能領域的快速發展推動了大語言模型&#xff08;LLM&#xff09;的廣泛應用&#xff0c;這些模型在文本生成、知識問答和創意表達等方面展現出前所未有的能力。然而&#xff0c;隨著應用場景的深化&#xff0c;…

git中的fork指令解釋

在Git中&#xff0c;Fork 是指將他人的代碼倉庫&#xff08;Repository&#xff09;復制到自己的賬戶下&#xff0c;創建一個完全獨立的副本[1][2]。以下是關于Fork的詳細說明&#xff1a; Fork的定義與核心作用 定義&#xff1a;Fork是代碼托管平臺&#xff08;如GitHub&#…