Redis實現(xiàn)布隆過濾器的代碼詳解
一、前言
布隆過濾器(Bloom Filter)是 Redis 4.0 版本提供的新功能,它被作為插件加載到 Redis 服務(wù)器中,給 Redis 提供強(qiáng)大的去重功能。
相比于 Set 集合的去重功能而言,布隆過濾器在空間上能節(jié)省 90% 以上,但是它的不足之處是去重率大約在 99% 左右,也就是說有 1% 左右的誤判率,這種誤差是由布隆過濾器的自身結(jié)構(gòu)決定的。俗話說“魚與熊掌不可兼得”,如果想要節(jié)省空間,就需要犧牲 1% 的誤判率,而且這種誤判率,在處理海量數(shù)據(jù)時,幾乎可以忽略。
二、RedisBloom 安裝與使用
(1)第一步:安裝Redis
關(guān)于Linux當(dāng)中redis的安裝:Linux上安裝Redis詳細(xì)教程_Redis_腳本之家 (jb51.net)
(2)第二步:安裝RedisBloom
在 Redis 4.0 版本之后,布隆過濾器才作為插件被正式使用。布隆過濾器需要單獨安裝,可以去GitHub,找到對應(yīng)的版本下載,鏈接:Releases · RedisBloom/RedisBloom (github.com),下載后再通過xftp上傳到Linux系統(tǒng)里,當(dāng)然也可以直接通過wget來下載。
這里注意我下載的2.2.18版本,最新版本2.6我沒有用,原因是make編譯的時候會報異常。
# 下載 wget https://codeload.github.com/RedisBloom/RedisBloom/tar.gz/refs/tags/v2.2.18 # 解壓 tar -zxvf v2.2.18
# 進(jìn)入到解壓目錄 cd RedisBloom-2.2.18/ # 編譯 make
編譯成功,可以看到redisbloom.so文件
(3)第三步:Redis集成RedisBloom插件
在redis.conf配置文件中加入如RedisBloom的redisbloom.so文件的地址
# vim查看redis.conf vim /opt/redis-stable/redis.conf # 在文件后面加上如下配置 loadmodule /opt/RedisBloom-2.2.18/redisbloom.so
(4)第四步: 重啟Redis進(jìn)行測試
# 關(guān)閉redis ps -ef | grep redis | awk -F" " '{print $2;}' | xargs kill -9 # 啟動redis /opt/redis-stable/src/redis-server redis.conf # 連接客戶端 /opt/redis-stable/src/redis-cli -c -h 127.0.0.1 -p 6379 -a 123456
三、RedisBloom 常用命令匯總
127.0.0.1:6379> bf.add spider:url www.baidu.net (integer) 1 127.0.0.1:6379> bf.exists spider:url www.baidu.net (integer) 1 127.0.0.1:6379> bf.madd spider:url www.taobao.com www.123qq.com 1) (integer) 1 2) (integer) 1 127.0.0.1:6379> bf.mexists spider:url www.jd.com www.taobao.com 1) (integer) 0 2) (integer) 1
注意使用AnotherRedisDesktopManager客戶端是沒辦法查看該數(shù)據(jù)類型的值的。
四、通過 Jedis 使用 RedisBloom
Java 客戶端 Jedis沒有提供指令擴(kuò)展機(jī)制,所以你無法直接使用 Jedis 來訪問Redis Module 提供的 bf.xxx 指令。RedisLabs 提供了一個單獨的包 JReBloom,但是它是基于 Jedis的。
我們使用的話只需要引入JReBloom就可以,JReBloom內(nèi)部引用了Jedis 。假如系統(tǒng)引用了jedis,又要引用jrebloom,這時候需要注意版本沖突的問題。
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.9.0</version> </dependency> <dependency> <groupId>com.redislabs</groupId> <artifactId>jrebloom</artifactId> <version>2.2.2</version> </dependency>
代碼示例:
import io.rebloom.client.Client; import redis.clients.jedis.Jedis; public class JrebloomDemo { public static void main(String[] args) { //連接本地的 Redis 服務(wù) Jedis jedis = new Jedis("192.168.115.239", 6379); //jedis.auth("123456"); //創(chuàng)建client也支持連接池的:public Client(Pool<Jedis> pool) Client client = new Client(jedis); // 測試數(shù)據(jù) int capacity = 10000; // 容錯率,只能設(shè)置0 < error rate range < 1 不然直接會異常! double errorRate = 0.01; // 測試的key值 String key = "ceshi"; // 創(chuàng)建過濾器:可以創(chuàng)建指定位數(shù)和容錯率的布隆過濾器,如果過濾器已經(jīng)存在創(chuàng)建的話就會異常 if (!jedis.exists(key)) { client.createFilter(key, capacity, errorRate); } for (int i = 0; i < capacity; i++) { client.bfInsert(key, String.valueOf(i)); } System.out.println("存入元素為=={" + capacity + "}"); // 統(tǒng)計誤判次數(shù) int count = 0; // 我在數(shù)據(jù)范圍之外的數(shù)據(jù),測試相同量的數(shù)據(jù),判斷錯誤率是不是符合我們當(dāng)時設(shè)定的錯誤率 for (int i = capacity; i < capacity * 2; i++) { if (client.exists(key, String.valueOf(i))) { count++; } } System.out.println("誤判元素為=={" + count + "}"); // 刪除過濾器 client.delete(key); } }
運(yùn)行示例:
現(xiàn)在存在個問題,假如我們redis并沒有安裝RedisBloom,那他可以運(yùn)行嗎?
答案是不可以的,他根本無法識別bf.xxx 指令
錯誤率越低,所需要的空間也會越大,因此就需要我們盡可能精確的估算元素數(shù)量,避免空間的浪費(fèi)。我們也要根據(jù)具體的業(yè)務(wù)來確定錯誤率的許可范圍,對于不需要太精確的業(yè)務(wù)場景,錯誤率稍微設(shè)置大一點也可以。
查看剛剛創(chuàng)建的過濾器:這個數(shù)據(jù)結(jié)構(gòu)不支持get查詢。
五、Redisson 封裝的布隆過濾器
Redisson布隆過濾器官網(wǎng)介紹:6. 分布式對象 · redisson/redisson Wiki · GitHub
引入依賴:
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.22.1</version> </dependency>
代碼示例:
import org.redisson.Redisson; import org.redisson.api.RBloomFilter; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class RedissonBloomFilter { public static void main(String[] args) { Config config = new Config(); config.useSingleServer() .setAddress("redis://127.0.0.1:6379") //.setPassword("123456") .setDatabase(0); //獲取客戶端 RedissonClient redissonClient = Redisson.create(config); // 測試數(shù)據(jù) int capacity = 10000; // 容錯率,只能設(shè)置0 < error rate range < 1 不然直接會異常! double errorRate = 0.01; // 測試的key值 String key = "ceshi"; RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(key); // 初始化布隆過濾器,預(yù)計統(tǒng)計元素數(shù)量為10000,期望誤差率為0.01 bloomFilter.tryInit(capacity, errorRate); for (long i = 0; i < capacity; i++) { bloomFilter.add(String.valueOf(i)); } System.out.println("存入元素為=={" + capacity + "}"); // 統(tǒng)計誤判次數(shù) int count = 0; // 我在數(shù)據(jù)范圍之外的數(shù)據(jù),測試相同量的數(shù)據(jù),判斷錯誤率是不是符合我們當(dāng)時設(shè)定的錯誤率 for (int i = capacity; i < capacity * 2; i++) { if (bloomFilter.contains(String.valueOf(i))) { count++; } } System.out.println("誤判元素為=={" + count + "}"); // 刪除過濾器 // bloomFilter.delete(); } }
運(yùn)行結(jié)果:
通過運(yùn)行結(jié)果不難發(fā)現(xiàn),同樣是10000數(shù)據(jù),和0.01容錯,Redisson 實現(xiàn)的布隆過濾器明顯沒有基于RedisBloom的過濾器容錯率好。
查看剛剛創(chuàng)建的過濾器:
六、使用哪種方式的過濾器比較好?
RedisBloom和Redisson實現(xiàn)的過濾器區(qū)別:
- 數(shù)據(jù)結(jié)構(gòu): RedisBloom相當(dāng)于為了實現(xiàn)過濾器而新增了一個數(shù)據(jù)結(jié)構(gòu),而Redisson是基于redis原有的bitmap位圖數(shù)據(jù)結(jié)構(gòu)來通過硬編碼實現(xiàn)的過濾器。
- 存儲: 存儲兩者其實并沒有差距,都沒有存儲原數(shù)據(jù),我使用Redisson存儲了10000條數(shù)據(jù)然后設(shè)置的0.01容錯占用了11.7kb也符合布隆過濾器的占用。
- 容錯: 同樣是10000條數(shù)據(jù)0.01容錯,RedisBloom誤判元素是58,Redisson實現(xiàn)的是227。
- 耦合度: 使用RedisBloom就需要安裝RedisBloom,如果不安裝RedisBloom程序直接就不能使用了,而使用Redisson他只依賴于redis。
- 分片: RedisBloom只是redis一種數(shù)據(jù)結(jié)構(gòu),本身redis集群就是支持分片的,所以RedisBloom肯定也沒問題,Redisson的布隆過濾器也支持分片,但是需要付費(fèi)。
- 性能: 使用 redis 的位圖來實現(xiàn)的布隆過濾器性能上要差不少。比如一次 exists 查詢會涉及到多次 getbit 操作,網(wǎng)絡(luò)開銷相比而言會高出不少。
綜上比較,個人建議使用RedisBloom比較好一點!
到此這篇關(guān)于Redis布隆過濾器用法詳解的文章就介紹到這了,更多相關(guān)Redis布隆過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Redis獲取數(shù)據(jù)轉(zhuǎn)json,解決動態(tài)泛型傳參的問題
這篇文章主要介紹了使用Redis獲取數(shù)據(jù)轉(zhuǎn)json,解決動態(tài)泛型傳參的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07redis鍵值出現(xiàn)\xac\xed\x00\x05t\x00&的問題及解決
這篇文章主要介紹了redis鍵值出現(xiàn)\xac\xed\x00\x05t\x00&的問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07如何監(jiān)聽Redis中Key值的變化(SpringBoot整合)
測試過程中我們有一部分常量值放入redis,共大部分應(yīng)用調(diào)用,但在測試過程中經(jīng)常有人會清空redis,回歸測試,下面這篇文章主要給大家介紹了關(guān)于如何監(jiān)聽Redis中Key值變化的相關(guān)資料,需要的朋友可以參考下2024-03-03使用SpringBoot?+?Redis?實現(xiàn)接口限流的方式
這篇文章主要介紹了SpringBoot?+?Redis?實現(xiàn)接口限流,Redis?除了做緩存,還能干很多很多事情:分布式鎖、限流、處理請求接口冪等,文中給大家提到了限流注解的創(chuàng)建方式,需要的朋友可以參考下2022-05-05