最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis實現(xiàn)布隆過濾器緩存去重的"智能門衛(wèi)"(實例詳解)

 更新時間:2026年02月02日 08:47:43   作者:佛祖讓我來巡山  
布隆過濾器(Bloom Filter)本質(zhì)是一個基于哈希函數(shù)的概率型數(shù)據(jù)結(jié)構(gòu),核心作用是快速判斷一個元素是否存在于集合中,今天給大家介紹Redis實現(xiàn)布隆過濾器緩存去重的"智能門衛(wèi)",感興趣的朋友跟隨小編一起看看吧

在緩存架構(gòu)中,總有一些“頭疼問題”:用戶反復(fù)提交相同請求、查詢不存在的key導(dǎo)致緩存穿透、海量數(shù)據(jù)去重效率低下……這些場景下,Redis布隆過濾器就是當(dāng)之無愧的“救星”。它像一個智能門衛(wèi),能快速判斷“這個人是不是來過”“這個key是不是不存在”,用極小的空間成本實現(xiàn)高效過濾,性能遠(yuǎn)超傳統(tǒng)的數(shù)據(jù)庫查詢或全量緩存校驗。

今天咱們就從“是什么、為什么好用、怎么用Redis快速實現(xiàn)”三個維度,用通俗的語言+實操代碼,把布隆過濾器講透。全程避開復(fù)雜公式,就算是剛接觸緩存的同學(xué),也能跟著步驟快速落地。

一、先搞懂:布隆過濾器到底是個啥?

布隆過濾器(Bloom Filter)本質(zhì)是一個基于哈希函數(shù)的概率型數(shù)據(jù)結(jié)構(gòu),核心作用是“快速判斷一個元素是否存在于集合中”。它不像哈希表那樣存儲完整數(shù)據(jù),而是用一個二進(jìn)制數(shù)組(bit數(shù)組)+多個哈希函數(shù),通過標(biāo)記元素的哈希位置來實現(xiàn)過濾。

咱們用“小區(qū)門衛(wèi)記訪客”的場景類比,秒懂核心邏輯:

  • 二進(jìn)制數(shù)組 = 門衛(wèi)的登記本,每一頁只有“是”(1)和“否”(0)兩個狀態(tài);
  • 哈希函數(shù) = 門衛(wèi)的“記憶規(guī)則”,比如“記住訪客的姓氏首字母+身高區(qū)間+鞋子顏色”;
  • 元素存在判斷 = 門衛(wèi)根據(jù)記憶規(guī)則核對登記本,只要有一條規(guī)則對應(yīng)“否”,就確定訪客沒來過;如果全是“是”,則大概率來過(存在極小誤判)。

核心特性:優(yōu)點與“小瑕疵”

布隆過濾器的優(yōu)勢和局限性都很鮮明,落地前必須摸清:

? 核心優(yōu)點

  • 空間占用極小:僅用bit數(shù)組存儲標(biāo)記,存儲100萬條數(shù)據(jù),誤判率1%時,僅需約1.2MB空間;
  • 查詢速度極快:時間復(fù)雜度是O(k)(k是哈希函數(shù)個數(shù)),無論數(shù)據(jù)量多大,都能瞬間返回結(jié)果;
  • 支持海量數(shù)據(jù):無需存儲完整數(shù)據(jù),可輕松應(yīng)對千萬級、億級數(shù)據(jù)的過濾場景。

? 不可忽視的局限性

  • 存在誤判率:只能確定“元素一定不存在”,不能100%確定“元素一定存在”,誤判率可通過參數(shù)調(diào)整,但無法完全消除;
  • 不支持刪除操作:一旦元素被標(biāo)記到bit數(shù)組,無法反向清除(會影響其他元素的判斷);
  • 需提前預(yù)估數(shù)據(jù)量:哈希函數(shù)個數(shù)、bit數(shù)組長度需根據(jù)預(yù)估數(shù)據(jù)量計算,否則會導(dǎo)致誤判率飆升。

二、Redis實現(xiàn)布隆過濾器的兩種方式

Redis本身沒有內(nèi)置布隆過濾器,但提供了兩種快速實現(xiàn)的方案:一是基于Redis的BitMap(位圖)手動實現(xiàn),靈活可控;二是使用Redis官方推薦的Redisson客戶端,封裝好現(xiàn)成API,開箱即用。咱們分別講實操,按需選擇即可。

方案一:基于BitMap手動實現(xiàn)(靈活可控)

核心思路:利用Redis的BitMap數(shù)據(jù)結(jié)構(gòu)作為布隆過濾器的bit數(shù)組,通過多個哈希函數(shù)計算元素的哈希值,將對應(yīng)位置的bit置為1;查詢時,同樣計算哈希值,檢查所有位置是否為1,全為1則大概率存在,否則一定不存在。

1. 關(guān)鍵參數(shù)計算(避免誤判率過高)

手動實現(xiàn)前,需先確定三個核心參數(shù),可通過公式或在線工具計算:

  • m:bit數(shù)組長度(單位:bit),預(yù)估數(shù)據(jù)量n越大,m需越大;
  • k:哈希函數(shù)個數(shù),k過多會導(dǎo)致bit數(shù)組快速被占滿,誤判率上升;k過少則過濾效果差;
  • p:可接受的誤判率(通常設(shè)為0.01~0.1)。

常用計算公式(無需死記,在線工具直接算):

  • m = - (n * ln p) / (ln 2)² (bit數(shù)組長度);
  • k = (m / n) * ln 2 (哈希函數(shù)個數(shù))。

舉個例子:預(yù)估存儲10萬條數(shù)據(jù),誤判率設(shè)為0.01,計算得m≈958505 bit(約117KB),k≈7個哈希函數(shù)。

2. 手動實現(xiàn)代碼(Java示例)

核心是實現(xiàn)多個哈希函數(shù),操作Redis的BitMap指令(SETBIT置1,GETBIT查詢):

import org.springframework.data.redis.core.StringRedisTemplate;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
 * 基于Redis BitMap手動實現(xiàn)布隆過濾器
 */
public class RedisBloomFilter {
    // Redis鍵名
    private final String key;
    // bit數(shù)組長度
    private final long bitSize;
    // 哈希函數(shù)個數(shù)
    private final int hashCount;
    private final StringRedisTemplate stringRedisTemplate;
    // 構(gòu)造器:初始化參數(shù)
    public RedisBloomFilter(String key, long n, double p, StringRedisTemplate stringRedisTemplate) {
        this.key = key;
        this.stringRedisTemplate = stringRedisTemplate;
        // 計算bit數(shù)組長度
        this.bitSize = (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
        // 計算哈希函數(shù)個數(shù)
        this.hashCount = (int) (this.bitSize / n * Math.log(2));
    }
    // 添加元素到布隆過濾器
    public void add(Object value) {
        byte[] bytes = value.toString().getBytes(StandardCharsets.UTF_8);
        long[] hashes = hash(bytes, hashCount, bitSize);
        for (long hash : hashes) {
            // 把對應(yīng)bit位置置為1
            stringRedisTemplate.opsForValue().setBit(key, hash, true);
        }
    }
    // 判斷元素是否存在(存在返回true,不存在返回false;true可能是誤判)
    public boolean contains(Object value) {
        byte[] bytes = value.toString().getBytes(StandardCharsets.UTF_8);
        long[] hashes = hash(bytes, hashCount, bitSize);
        for (long hash : hashes) {
            // 只要有一個bit位為0,就確定不存在
            if (!stringRedisTemplate.opsForValue().getBit(key, hash)) {
                return false;
            }
        }
        return true;
    }
    // 多哈希函數(shù)實現(xiàn)(基于MD5拆分)
    private long[] hash(byte[] bytes, int hashCount, long bitSize) {
        long[] hashes = new long[hashCount];
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] digest = md5.digest(bytes);
            // 把MD5結(jié)果(16字節(jié))拆分成多個哈希值
            for (int i = 0; i < hashCount; i++) {
                long hash = 0;
                for (int j = i * 2; j < (i + 1) * 2 && j < digest.length; j++) {
                    hash = hash * 256 + (digest[j] & 0xFF);
                }
                // 確保哈希值在bit數(shù)組長度范圍內(nèi)
                hashes[i] = hash % bitSize;
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("哈希函數(shù)初始化失敗", e);
        }
        return hashes;
    }
}

3. 使用方式

// 初始化布隆過濾器:key為"user:bloom:filter",預(yù)估10萬條數(shù)據(jù),誤判率0.01
RedisBloomFilter bloomFilter = new RedisBloomFilter("user:bloom:filter", 100000, 0.01, stringRedisTemplate);
// 添加元素
bloomFilter.add("user123");
bloomFilter.add("order456");
// 判斷元素是否存在
boolean exists = bloomFilter.contains("user123"); // 大概率返回true
boolean notExists = bloomFilter.contains("user789"); // 一定返回false

方案二:Redisson客戶端實現(xiàn)(開箱即用)

如果覺得手動實現(xiàn)麻煩,推薦用Redisson——Redis官方生態(tài)的Java客戶端,已經(jīng)封裝好了布隆過濾器,支持自動計算參數(shù)、分布式場景,還解決了手動實現(xiàn)的哈希函數(shù)優(yōu)化問題,生產(chǎn)環(huán)境首選。

1. 引入依賴

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.3</version> // 版本與Redis版本適配
</dependency>

2. 快速實現(xiàn)代碼

import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class RedissonBloomFilterDemo {
    @Autowired
    private RedissonClient redissonClient;
    // 初始化布隆過濾器
    public RBloomFilter<String> initBloomFilter() {
        // 布隆過濾器名稱
        String filterName = "user:bloom:filter:redisson";
        // 獲取布隆過濾器實例
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(filterName);
        // 初始化:預(yù)估10萬條數(shù)據(jù),誤判率0.01(Redisson會自動計算m和k)
        bloomFilter.tryInit(100000, 0.01);
        return bloomFilter;
    }
    // 測試使用
    public void testBloomFilter() {
        RBloomFilter<String> bloomFilter = initBloomFilter();
        // 添加元素
        bloomFilter.add("user123");
        bloomFilter.add("order456");
        // 判斷元素是否存在
        boolean exists = bloomFilter.contains("user123"); // 大概率true
        boolean notExists = bloomFilter.contains("user789"); // 一定false
        // 統(tǒng)計已添加元素數(shù)量(近似值)
        long count = bloomFilter.count();
        System.out.println("已添加元素數(shù)量:" + count);
    }
}

3. 核心優(yōu)勢

  • 分布式支持:適配微服務(wù)場景,多實例共享同一個布隆過濾器,無需擔(dān)心數(shù)據(jù)一致性;
  • 參數(shù)優(yōu)化:內(nèi)置更高效的哈希函數(shù)(MurmurHash),誤判率控制更精準(zhǔn);
  • API豐富:支持元素計數(shù)、批量添加等功能,比手動實現(xiàn)更完善。

三、實際應(yīng)用場景與避坑指南

? 典型應(yīng)用場景

  • 緩存穿透防護(hù):查詢數(shù)據(jù)庫前,先用布隆過濾器判斷key是否存在,不存在則直接返回,避免大量無效數(shù)據(jù)庫查詢;
  • 海量數(shù)據(jù)去重:比如用戶簽到、日志去重、爬蟲URL去重,無需存儲全量數(shù)據(jù),僅用bit數(shù)組標(biāo)記;
  • 防止重復(fù)提交:接口請求前,用布隆過濾器判斷請求ID是否已處理,避免重復(fù)業(yè)務(wù)邏輯執(zhí)行;
  • 黑名單過濾:比如垃圾郵件識別、惡意IP攔截,快速判斷是否在黑名單中。

? 避坑指南

  • 不要用在“絕對不能誤判”的場景:比如金融交易、用戶登錄驗證,誤判可能導(dǎo)致嚴(yán)重問題;
  • 提前預(yù)估數(shù)據(jù)量:若實際數(shù)據(jù)量遠(yuǎn)超預(yù)估,bit數(shù)組會被快速占滿,誤判率會急劇上升,可預(yù)留2~3倍冗余;
  • 定期重置布隆過濾器:若數(shù)據(jù)有過期特性(比如每日黑名單更新),可定期刪除舊的布隆過濾器,重建新實例;
  • Redis集群注意事項:手動實現(xiàn)的布隆過濾器若用在Redis集群中,需確保key落在同一個節(jié)點(避免哈希分片導(dǎo)致bit數(shù)組分散),Redisson已自動處理該問題。

四、總結(jié):什么時候選哪種實現(xiàn)方式?

Redis布隆過濾器的核心價值的是“用極小空間換極高過濾效率”,落地時按場景選擇實現(xiàn)方式:

  • 快速落地、生產(chǎn)環(huán)境、分布式場景:選Redisson,省心高效,適配性強;
  • 學(xué)習(xí)研究、自定義哈希函數(shù)、特殊參數(shù)需求:選手動實現(xiàn),靈活可控,加深對原理的理解。

其實布隆過濾器的邏輯并不復(fù)雜,核心就是“哈希標(biāo)記+概率判斷”。掌握它之后,面對緩存穿透、海量去重等問題,就不用再靠“全量存儲”這種笨辦法,能大幅提升系統(tǒng)性能和空間利用率。下次再遇到類似場景,直接掏出Redis布隆過濾器,輕松搞定!

到此這篇關(guān)于Redis快速實現(xiàn)布隆過濾器:緩存去重的“智能門衛(wèi)”的文章就介紹到這了,更多相關(guān)Redis布隆過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis服務(wù)端主動回收配置的使用小結(jié)

    Redis服務(wù)端主動回收配置的使用小結(jié)

    本文主要介紹了Redis服務(wù)端主動回收配置的使用小結(jié),包括客戶端主動回收、連接池配置、連接泄漏檢測及服務(wù)端策略設(shè)置,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-08-08
  • 淺談Redis跟MySQL的雙寫問題解決方案

    淺談Redis跟MySQL的雙寫問題解決方案

    項目中有遇到這個問題,跟MySQL中的數(shù)據(jù)不一致,記錄一下,本文主要介紹了Redis跟MySQL的雙寫問題解決方案,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • RedisTemplate常用方法大全(面試必備)

    RedisTemplate常用方法大全(面試必備)

    RedisTemplate是SpringData Redis提供的一個類,本文主要介紹了RedisTemplate常用方法大全,具有一定的參考價值,感興趣的可以了解一下
    2024-05-05
  • 在K8s上部署Redis集群的方法步驟

    在K8s上部署Redis集群的方法步驟

    這篇文章主要介紹了在K8s上部署Redis集群的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Redis如何設(shè)置過期時間

    Redis如何設(shè)置過期時間

    這篇文章主要介紹了Redis如何設(shè)置過期時間問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • redis-sentinel基礎(chǔ)概念及部署流程

    redis-sentinel基礎(chǔ)概念及部署流程

    Redis Sentinel是Redis的高可用解決方案,通過監(jiān)控主從節(jié)點、自動故障轉(zhuǎn)移、通知機制及配置提供,實現(xiàn)集群故障恢復(fù)與服務(wù)持續(xù)可用,核心組件包括Sentinel節(jié)點、主節(jié)點和從節(jié)點,部署需配置參數(shù),驗證主節(jié)點變化即成功
    2025-08-08
  • Spring?Boot?3.0x的Redis?分布式鎖的概念和原理

    Spring?Boot?3.0x的Redis?分布式鎖的概念和原理

    Redis?分布式鎖是一種基于?Redis?的分布式鎖解決方案,它的原理是利用?Redis?的原子性操作實現(xiàn)鎖的獲取和釋放,從而保證共享資源的獨占性,這篇文章主要介紹了適合?Spring?Boot?3.0x的Redis?分布式鎖,需要的朋友可以參考下
    2024-08-08
  • Redis中散列類型的常用命令小結(jié)

    Redis中散列類型的常用命令小結(jié)

    散列類型的鍵值其實也是一種字典解耦,其存儲了字段和字段值的映射,但字段值只能是字符串,不支持其他數(shù)據(jù)類型,所以說散列類型不能嵌套其他的數(shù)據(jù)類型。下面就來詳細(xì)介紹下Redis中散列類型的常用命令,有需要的可以參考學(xué)習(xí)。
    2016-09-09
  • linux?redis-連接命令解讀

    linux?redis-連接命令解讀

    這篇文章主要介紹了linux?redis-連接命令解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Redis key鍵的具體使用

    Redis key鍵的具體使用

    Redis 是一種鍵值(key-value)型的緩存型數(shù)據(jù)庫,它將數(shù)據(jù)全部以鍵值對的形式存儲在內(nèi)存中,本文就來介紹一下key鍵的具體使用,感興趣的可以了解一下
    2024-02-02

最新評論

嘉祥县| 大兴区| 中西区| 时尚| 阜阳市| 安徽省| 江安县| 闸北区| 乌海市| 克拉玛依市| 全南县| 河北区| 开江县| 攀枝花市| 新绛县| 台北县| 江达县| 盱眙县| 周至县| 平顺县| 三江| 九江市| 民和| 鹤庆县| 邯郸县| 全椒县| 麻阳| 武鸣县| 英吉沙县| 台北县| 新河县| 唐河县| 泰兴市| 建湖县| 阿城市| 仁化县| 碌曲县| 沿河| 盖州市| 桦川县| 财经|