Redis 4.0的布隆过滤器插件

还没有安装Redis的同学,可以参考我先前的文章安装,传送门《玩转Redis-Redis安装、后台启动、卸载》。Redis 4.0开始以插件形式提供布隆过滤器。

# docker方式安装

> docker pull redislabs/rebloom # 拉取镜像
> docker run -p6379:6379 redislabs/rebloom # 运行容器
> redis-cli # 连接容器中的 redis 服务

# linux服务器直接安装

>git clone git://github.com/RedisLabsModules/rebloom
>cd rebloom
>make
# 当前路径会生成一个rebloom.so文件
# 在redis的配置中(通常在/etc/redis/redis.conf)增加一行配置 loadmodule /"rebloom.so的绝对路径"/rebloom.so
# 重启Redis即可

   上述的安装提到需要重启Redis,但是生产环境的Redis可不是你想重启就重启的。有什么方式可以不重启Redis就加载rebloom插件吗,MODULE LOAD命令就派上用场了。

# 不重启Redis加载rebloom插件

1、查看redis当前已加载的插件
> MODULE LOAD /"rebloom.so的绝对路径"/redisbloom.so
> module list
1) 1) "name"
2) "bf"
3) "ver"
4) (integer) 999999
# 看到以上数据则说明redisbloom加载成功了,模块名name为"bf",模块版本号ver为999999。

# 动态执行模块卸载
# MODULE UNLOAD 模块名

# 当然,为了防止Redis重启导致动态加载的模块丢失,我们还是应该在redis.conf 中加上相关配置。

2.2、布隆过滤器的命令详解及示例
完整指令说明可前往官网查看:https://oss.redislabs.com/redisbloom/Bloom_Commands/。

2.2.1、Bloom命令简述
【核心命令】添加元素:BF.ADD(添加单个)、BF.MADD(添加多个)、BF.INSERT(添加多个);

【核心命令】检查元素是否存在:BF.EXISTS(查询单个元素)、BF.MEXISTS(查询多个元素)

命令 功能 参数
BF.RESERVE 创建一个大小为capacity,错误率为error_rate的空的Bloom BF.RESERVE {key} {error_rate} {capacity} [EXPANSION expansion] [NONSCALING]
BF.ADD 向key指定的Bloom中添加一个元素item BF.ADD {key} {item}
BF.MADD 向key指定的Bloom中添加多个元素 BF.MADD {key} {item} [item…]
BF.INSERT 向key指定的Bloom中添加多个元素,添加时可以指定大小和错误率,且可以控制在Bloom不存在的时候是否自动创建 BF.INSERT {key} [CAPACITY {cap}] [ERROR {error}] [EXPANSION expansion] [NOCREATE] [NONSCALING] ITEMS {item…}
BF.EXISTS 检查一个元素是否可能存在于key指定的Bloom中 BF.EXISTS {key} {item}
BF.MEXISTS 同时检查多个元素是否可能存在于key指定的Bloom中 BF.MEXISTS {key} {item} [item…]
BF.SCANDUMP 对Bloom进行增量持久化操作 BF.SCANDUMP {key} {iter}
BF.LOADCHUNK 加载SCANDUMP持久化的Bloom数据 BF.LOADCHUNK {key} {iter} {data}
BF.INFO 查询key指定的Bloom的信息 BF.INFO {key}
BF.DEBUG 查看BloomFilter的内部详细信息(如每层的元素个数、错误率等) BF.DEBUG {key}
2.2.2、BF.RESERVE
参数
BF.RESERVE {key} {error_rate} {capacity}
功能
创建一个大小为capacity,错误率为error_rate的空的BloomFilter
时间复杂度
O(1)
参数说明
key:布隆过滤器的key;
error_rate:期望的错误率(False Positive Rate),该值必须介于0和1之间。该值越小,BloomFilter的内存占用量越大,CPU使用率越高。
capacity:布隆过滤器的初始容量,即期望添加到布隆过滤器中的元素的个数。当实际添加的元素个数超过该值时,布隆过滤器将进行自动的扩容,该过程会导致性能有所下降,下降的程度是随着元素个数的指数级增长而线性下降。
可选参数
expansion:当添加到布隆过滤器中的数据达到初始容量后,布隆过滤器会自动创建一个子过滤器,子过滤器的大小是上一个过滤器大小乘以expansion。expansion的默认值是2,也就是说布隆过滤器扩容默认是2倍扩容。
NONSCALING:设置此项后,当添加到布隆过滤器中的数据达到初始容量后,不会扩容过滤器,并且会抛出异常((error) ERR non scaling filter is full)。
返回值
成功:OK;
其它情况返回相应的异常信息。
备注
BloomFilter的扩容是通过增加BloomFilter的层数来完成的。每增加一层,在查询的时候就可能会遍历多层BloomFilter来完成,每一层的容量都是上一层的两倍(默认)。
# 公众号@zxiaofan
# 创建一个容量为5且不允许扩容的过滤器;
127.0.0.1:6379> bf.reserve bf2 0.1 5 NONSCALING
OK
127.0.0.1:6379> bf.madd bf2 1 2 3 4 5
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 1
5) (integer) 1

# 添加第6个元素时即提示BloomFilter已满;
127.0.0.1:6379> bf.madd bf2 6
1) (error) ERR non scaling filter is full
127.0.0.1:6379> bf.info bf2
1) Capacity
2) (integer) 5
3) Size
4) (integer) 155
5) Number of filters
6) (integer) 1
7) Number of items inserted
8) (integer) 5
9) Expansion rate
10) (integer) 2

2.2.3、BF.ADD
参数
BF.ADD {key} {item}
功能
向key指定的Bloom中添加一个元素item。
时间复杂度
O(log N),N是过滤器的层数。
参数说明
key:布隆过滤器的名字;
item:待插入过滤器的元素;
返回值
元素不存在插入成功:返回1;
元素可能已经存在:返回0;
其它情况返回相应的异常信息。
2.2.3、BF.MADD
参数
BF.MADD {key} {item} [item…]
功能
向key指定的Bloom中添加多个元素item。
时间复杂度
O(log N),N是过滤器的层数。
参数说明
key:布隆过滤器的名字;
item:待插入过滤器的元素,可插入多个;
返回值
成功:返回一个数组,数组的每一个元素可能为1或0,当item一定不存在时数组元素值为1,当item可能已经存在时数组元素值为0。
其它情况返回相应的异常信息。
2.2.5、BF.EXISTS
参数
BF.EXISTS {key} {item}
功能
检查一个元素是否可能存在于key指定的Bloom中
时间复杂度
O(log N),N是过滤器的层数。
参数说明
key:布隆过滤器的名字;
item:待检查的元素;
返回值
元素一定不存在:0;
元素可能存在:1;
其它情况返回相应的异常信息。
2.2.6、BF.MEXISTS
参数
BF.MEXISTS [item…]
功能
检查多个元素是否可能存在于key指定的Bloom中
时间复杂度
O(log N),N是过滤器的层数。
参数说明
key:布隆过滤器的名字;
item:待检查的元素,可设置多个;
返回值
成功:返回一个数组,数组的每一个元素可能为1或0,当item一定不存在时数组元素值为0,当item可能已经存在时数组元素值为1。
其它情况返回相应的异常信息。
# 公众号@zxiaofan
# 向BloomFilter添加单个元素
127.0.0.1:6379> bf.add bf1 itemadd1
(integer) 1

# 向BloomFilter批量添加多个元素
127.0.0.1:6379> bf.madd bf1 itemmadd1 itemmadd2
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> bf.exists itemmadd1
(error) ERR wrong number of arguments for 'bf.exists' command
127.0.0.1:6379> bf.exists bf1 itemmadd1
(integer) 1

# 批量检查多个元素是否存在于BloomFilter
127.0.0.1:6379> bf.mexists bf1 itemadd1 itemmadd1 itemmadd2
1) (integer) 1
2) (integer) 1
3) (integer) 1

2.2.7、BF.INSERT
参数
BF.INSERT {key} [CAPACITY {cap}] [ERROR {error}] [EXPANSION expansion] [NOCREATE] [NONSCALING] ITEMS {item…}
功能
向key指定的Bloom中添加多个元素,添加时可以指定大小和错误率,且可以控制在Bloom不存在的时候是否自动创建
时间复杂度
O(log N),N是过滤器的层数。
参数说明
key:布隆过滤器的名字;
CAPACITY:[如果过滤器已创建,则此参数将被忽略]。更多的信息参考<BF.RESERVE>;
ERROR:[如果过滤器已创建,则此参数将被忽略]。更多的信息参考<BF.RESERVE>;
expansion:布隆过滤器会自动创建一个子过滤器,子过滤器的大小是上一个过滤器大小乘以expansion。expansion的默认值是2,也就是说布隆过滤器扩容默认是2倍扩容。
NOCREATE:如果设置了该参数,当布隆过滤器不存在时则不会被创建。用于严格区分过滤器的创建和元素插入场景。该参数不能与CAPACITY和ERROR同时设置。
NONSCALING:设置此项后,当添加到布隆过滤器中的数据达到初始容量后,不会扩容过滤器,并且会抛出异常((error) ERR non scaling filter is full)。
ITEMS:待插入过滤器的元素列表,该参数必传。
返回值
成功:返回一个数组,数组的每一个元素可能为1或0,当item一定不存在时数组元素值为1,当item可能已经存在时数组元素值为0。
其它情况返回相应的异常信息。
127.0.0.1:6379> del bfinsert
(integer) 1

127.0.0.1:6379> bf.insert bfinsert CAPACITY 5 ERROR 0.1 EXPANSION 2 NONSCALING ITEMS item1 item2
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> bf.exists bfinsert item5
(integer) 0
127.0.0.1:6379> bf.insert bfinsert CAPACITY 5 ERROR 0.1 EXPANSION 2 NONSCALING ITEMS item1 item2 item3 item4 item5
1) (integer) 0
2) (integer) 0
3) (integer) 1
4) (integer) 1
5) (integer) 0
127.0.0.1:6379> bf.add bfinsert item5
(integer) 0
127.0.0.1:6379> bf.info bfinsert
1) Capacity
2) (integer) 5
3) Size
4) (integer) 155
5) Number of filters
6) (integer) 1
7) Number of items inserted
8) (integer) 4
9) Expansion rate
10) (integer) 2
127.0.0.1:6379> bf.add bfinsert item6
(integer) 1
127.0.0.1:6379> bf.add bfinsert item5
(integer) 0
127.0.0.1:6379> bf.exists bfinsert item5
(integer) 1

# 这里有个比较有意思的现象,item5未显示添加成功,但是后续却显示exists
# 这说明发生了hash冲突,误判就是这样产生的。
2.2.8、BF.SCANDUMP
参数
BF.SCANDUMP {key} {iter}
功能
对Bloom进行增量持久化操作(增量保存);
时间复杂度
O(log N),N是过滤器的层数。
参数说明
key:布隆过滤器的名字;
iter:首次调用传值0,或者上次调用此命令返回的结果值;
返回值
返回连续的(iter, data)对,直到(0,NULL),表示DUMP完成。
备注
127.0.0.1:6378> bf.madd bfdump d1 d2 d3 d4 d5 d6 d7
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 1
5) (integer) 1
6) (integer) 1
7) (integer) 1
127.0.0.1:6378> bf.scandump bfdump 0
1) (integer) 1
2) "ax00x00x00x00x00x00x00x01x00x00x00x05x00x00x00x02x00x00x00x8ax00x00x00x00x00x00x00Px04x00x00x00x00x00x00ax00x00x00x00x00x00x00{x14xaeGxe1zt?xe9x86/xb25x0e&@x00x00x00dx00x00x00x00x00x00x00x00"
127.0.0.1:6378> bf.scandump bfdump 1
1) (integer) 139
2) "x80x00 x00$x00 x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x82$x04x00@x00x00x00x00x00x00x00x00x00x00x00x02x04x00x00x00x00x00x00x04x01@xa0x00@x00x00x00x00x00x10@x00x02"x00 x00x00x04x00x00x00x00x00 x00x80x00x00"x04x04x04x00x00x00x00x00x00x00x00x00x00x80x00x00x00x00x00 x80$x00 x00x00 x0c$x00x00x00`x00x00x00x00x00x00x00x00x80x02 x04x00x00x00x00x00"
127.0.0.1:6378> bf.scandump bfdump 139
1) (integer) 0
2) ""
2.2.9、BF.LOADCHUNK
参数
BF.LOADCHUNK {key} {iter} {data}
功能
加载SCANDUMP持久化的Bloom数据;
时间复杂度
O(log N),N是过滤器的层数。
参数说明
key:目标布隆过滤器的名字;
iter:SCANDUMP返回的迭代器的值,和data一一对应;
data:SCANDUMP返回的数据块(data chunk);
返回值
成功则返回OK。
# Python 伪代码
# 来源于:https://oss.redislabs.com/redisbloom/Bloom_Commands/

chunks = []
iter = 0
# SCANDUMP
while True:
iter, data = BF.SCANDUMP(key, iter)
if iter == 0:
break
else:
chunks.append([iter, data])

# LOADCHUNK
for chunk in chunks:
iter, data = chunk
BF.LOADCHUNK(key, iter, data)
2.2.10、BF.INFO
参数
BF.INFO {key}
功能
返回BloomFilter的相关信息;
时间复杂度
O(1);
参数说明
key:目标布隆过滤器的名字;
返回值
Capacity:预设容量;
Size:实际占用情况,但如何计算待进一步确认;
Number of filters:过滤器层数;
Number of items inserted:已经实际插入的元素数量;
Expansion rate:子过滤器扩容系数(默认2);
127.0.0.1:6379> bf.info bf2
1) Capacity
2) (integer) 5
3) Size
4) (integer) 155
5) Number of filters
6) (integer) 1
7) Number of items inserted
8) (integer) 5
9) Expansion rate
10) (integer) 2
2.2.11、BF.DEBUG
参数
BF.DEBUG {key}
功能
查看BloomFilter的内部详细信息(如每层的元素个数、错误率等);
时间复杂度
O(log N),N是过滤器的层数;
参数说明
key:目标布隆过滤器的名字;
返回值
size:BloomFilter中已插入的元素数量;
每层BloomFilter的详细信息
bytes:占用字节数量;
bits:占用bit位数量,bits = bytes * 8;
hashes:该层hash函数数量;
hashwidth:hash函数宽度;
capacity:该层容量(第一层为BloomFilter初始化时设置的容量,第2层容量 = 第一层容量 * expansion,以此类推);
size:该层中已插入的元素数量(各层size之和等于BloomFilter中已插入的元素数量size);
ratio:该层错误率(第一层的错误率 = BloomFilter初始化时设置的错误率 * 0.5,第二层为第一层的0.5倍,以此类推,ratio与expansion无关);
# 公众号 @zxiaofan
# 创建一个容量为5的BloomFilter,其key为“bfexp”;
127.0.0.1:6379> bf.reserve bfexp 0.1 5
OK

# 查看BloomFilter的内部信息,此时BloomFilter的层数为1
127.0.0.1:6379> bf.debug bfexp
1) "size:0"
2) "bytes:4 bits:32 hashes:5 hash64 capacity:5 size:0 ratio:0.05"

127.0.0.1:6379> bf.madd bfexp 1 2 3 4 5
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 1
5) (integer) 1
127.0.0.1:6379> bf.debug bfexp
1) "size:5"
2) "bytes:4 bits:32 hashes:5 hash64 capacity:5 size:5 ratio:0.05"

127.0.0.1:6379> bf.madd bfexp 11 12 13 14 15
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 0
5) (integer) 1

# 添加10个元素后,此时BloomFilter的层数变为2;
# BloomFilter的元素数量为2层过滤器之和(5+4=9),添加“14”时实际因为hash冲突没添加成功;
127.0.0.1:6379> bf.debug bfexp
1) "size:9"
2) "bytes:4 bits:32 hashes:5 hash64 capacity:5 size:5 ratio:0.05"
3) "bytes:10 bits:80 hashes:6 hash64 capacity:10 size:4 ratio:0.025"

127.0.0.1:6379> bf.madd bfexp 21 22 23
1) (integer) 1
2) (integer) 1
3) (integer) 1
127.0.0.1:6379> bf.debug bfexp
1) "size:12"
2) "bytes:4 bits:32 hashes:5 hash64 capacity:5 size:5 ratio:0.05"
3) "bytes:10 bits:80 hashes:6 hash64 capacity:10 size:7 ratio:0.025"
127.0.0.1:6379> bf.madd bfexp 24 25
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> bf.debug bfexp
1) "size:14"
2) "bytes:4 bits:32 hashes:5 hash64 capacity:5 size:5 ratio:0.05"
3) "bytes:10 bits:80 hashes:6 hash64 capacity:10 size:9 ratio:0.025"
127.0.0.1:6379> bf.madd bfexp 31 32 33 34 35
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 1
5) (integer) 1

# 添加20个元素后,此时BloomFilter的层数变为3;
127.0.0.1:6379> bf.debug bfexp
1) "size:19"
2) "bytes:4 bits:32 hashes:5 hash64 capacity:5 size:5 ratio:0.05"
3) "bytes:10 bits:80 hashes:6 hash64 capacity:10 size:10 ratio:0.025"
4) "bytes:23 bits:184 hashes:7 hash64 capacity:20 size:4 ratio:0.0125"

原文链接:https://blog.csdn.net/u010887744/article/details/108700911

原文地址:https://www.cnblogs.com/duanxz/p/14700288.html