Redis布隆过滤器详解

2023-11-10

一、前言

布隆过滤器(Bloom Filter)是 Redis 4.0 版本提供的新功能,它被作为插件加载到 Redis 服务器中,给 Redis 提供强大的去重功能。

相比于 Set 集合的去重功能而言,布隆过滤器在空间上能节省 90% 以上,但是它的不足之处是去重率大约在 99% 左右,也就是说有 1% 左右的误判率,这种误差是由布隆过滤器的自身结构决定的。俗话说“鱼与熊掌不可兼得”,如果想要节省空间,就需要牺牲 1% 的误判率,而且这种误判率,在处理海量数据时,几乎可以忽略。

二、RedisBloom 安装与使用

(1)第一步:安装Redis

关于Linux当中redis的安装:https://blog.csdn.net/weixin_43888891/article/details/125830622

(2)第二步:安装RedisBloom

在 Redis 4.0 版本之后,布隆过滤器才作为插件被正式使用。布隆过滤器需要单独安装,可以去GitHub,找到对应的版本下载,链接:https://github.com/RedisBloom/RedisBloom/releases,下载后再通过xftp上传到Linux系统里,当然也可以直接通过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

在这里插入图片描述

# 进入到解压目录
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进行测试

# 关闭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客户端是没办法查看该数据类型的值的。

在这里插入图片描述

四、通过 Jedis 使用 RedisBloom

Java 客户端 Jedis没有提供指令扩展机制,所以你无法直接使用 Jedis 来访问Redis Module 提供的 bf.xxx 指令。RedisLabs 提供了一个单独的包 JReBloom,但是它是基于 Jedis的。

我们使用的话只需要引入JReBloom就可以,JReBloom内部引用了Jedis 。假如系统引用了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 服务
        Jedis jedis = new Jedis("192.168.115.239", 6379);
        //jedis.auth("123456");
        //创建client也支持连接池的:public Client(Pool<Jedis> pool)
        Client client = new Client(jedis);

        // 测试数据
        int capacity = 10000;
        // 容错率,只能设置0 < error rate range < 1  不然直接会异常!
        double errorRate = 0.01;
        // 测试的key值
        String key = "ceshi";
        // 创建过滤器:可以创建指定位数和容错率的布隆过滤器,如果过滤器已经存在创建的话就会异常
        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 + "}");
        // 统计误判次数
        int count = 0;
        // 我在数据范围之外的数据,测试相同量的数据,判断错误率是不是符合我们当时设定的错误率
        for (int i = capacity; i < capacity * 2; i++) {
            if (client.exists(key, String.valueOf(i))) {
                count++;
            }
        }
        System.out.println("误判元素为=={" + count + "}");
        // 删除过滤器
        client.delete(key);
    }
}

运行示例:

在这里插入图片描述

现在存在个问题,假如我们redis并没有安装RedisBloom,那他可以运行吗?

答案是不可以的,他根本无法识别bf.xxx 指令

在这里插入图片描述

错误率越低,所需要的空间也会越大,因此就需要我们尽可能精确的估算元素数量,避免空间的浪费。我们也要根据具体的业务来确定错误率的许可范围,对于不需要太精确的业务场景,错误率稍微设置大一点也可以。

查看刚刚创建的过滤器:这个数据结构不支持get查询。

在这里插入图片描述

五、Redisson 封装的布隆过滤器

Redisson布隆过滤器官网介绍

引入依赖:

<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);
        // 测试数据
        int capacity = 10000;
        // 容错率,只能设置0 < error rate range < 1  不然直接会异常!
        double errorRate = 0.01;
        // 测试的key值
        String key = "ceshi";

        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(key);
        // 初始化布隆过滤器,预计统计元素数量为10000,期望误差率为0.01
        bloomFilter.tryInit(capacity, errorRate);
        for (long i = 0; i < capacity; i++) {
            bloomFilter.add(String.valueOf(i));
        }
        System.out.println("存入元素为=={" + capacity + "}");

        // 统计误判次数
        int count = 0;
        // 我在数据范围之外的数据,测试相同量的数据,判断错误率是不是符合我们当时设定的错误率
        for (int i = capacity; i < capacity * 2; i++) {
            if (bloomFilter.contains(String.valueOf(i))) {
                count++;
            }
        }
        System.out.println("误判元素为=={" + count + "}");
        // 删除过滤器
        // bloomFilter.delete();
    }
}

运行结果:

通过运行结果不难发现,同样是10000数据,和0.01容错,Redisson 实现的布隆过滤器明显没有基于RedisBloom的过滤器容错率好。

在这里插入图片描述

查看刚刚创建的过滤器:

在这里插入图片描述

六、使用哪种方式的过滤器比较好?

RedisBloom和Redisson实现的过滤器区别:

  • 数据结构: RedisBloom相当于为了实现过滤器而新增了一个数据结构,而Redisson是基于redis原有的bitmap位图数据结构来通过硬编码实现的过滤器。
  • 存储: 存储两者其实并没有差距,都没有存储原数据,我使用Redisson存储了10000条数据然后设置的0.01容错占用了11.7kb也符合布隆过滤器的占用。
    在这里插入图片描述
  • 容错: 同样是10000条数据0.01容错,RedisBloom误判元素是58,Redisson实现的是227。
  • 耦合度: 使用RedisBloom就需要安装RedisBloom,如果不安装RedisBloom程序直接就不能使用了,而使用Redisson他只依赖于redis。
  • 分片: RedisBloom只是redis一种数据结构,本身redis集群就是支持分片的,所以RedisBloom肯定也没问题,Redisson的布隆过滤器也支持分片,但是需要付费。
  • 性能: 使用 redis 的位图来实现的布隆过滤器性能上要差不少。比如一次 exists 查询会涉及到多次 getbit 操作,网络开销相比而言会高出不少。

综上比较,个人建议使用RedisBloom比较好一点!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis布隆过滤器详解 的相关文章

  • Redis部署配置-主从复制

    目前我有两台服务器 我已经部署了基于node js Express JS的Web服务API 我正在使用 Redis 来缓存 JSON 字符串 将此设置部署到生产中的最佳选择是什么 我懂了here https stackoverflow co
  • Node.js 上通过套接字连接 Redis

    由于共享托管 目标主机上的我的 redis 服务器不在端口上运行 而是在非常特定的套接字上运行 可以通过套接字文件连接到该套接字 只有我的用户可以访问 但是 我还没有找到如何通过套接字指定连接node redis and connect r
  • 使用 AWS ElastiCache 请求中的 Airflow CROSSSLOT 密钥未散列到同一插槽错误

    我在 AWS ECS 上运行 apache airflow 1 8 1 并且有一个 AWS ElastiCache 集群 redis 3 2 4 运行 2 个分片 2 个启用多可用区的节点 集群 Redis 引擎 我已经验证气流可以毫无问题
  • 如何在多个Lua State(多线程)之间传递数据?

    我在中启动Redis连接池redis lua 通过从 C 调用 我得到了redis lua state 此 Lua 状态全局启动一次 仅在其他线程中启动get从中 当有一个 HTTP 请求 工作线程 时 我需要从redis lua stat
  • 如何让客户端下载动态生成的非常大的文件

    我有一个导出功能 可以读取整个数据库并创建一个包含所有记录的 xls 文件 然后文件被发送到客户端 当然 导出完整数据库的时间需要大量时间 并且请求很快就会以超时错误结束 处理这种情况的最佳解决方案是什么 例如 我听说过使用 Redis 创
  • Redis键空间事件不触发

    我有两个 Redis 客户端 在一个文件中我有一个简单的脚本设置并删除了 Redis 键 var redis require redis var client redis createClient 6379 127 0 0 1 client
  • WSL Redis 遇到系统尚未使用 systemd 作为 init 系统(PID 1)启动。无法操作[已关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在尝试遵循本文中讨论的 Redis 安装过程article https www digitalocean com community
  • Redis hash写入速度非常慢

    我面临一个非常奇怪的问题 使用 Redis 时 我的写入速度非常糟糕 在理想的情况下 写入速度应该接近 RAM 上的写入速度 这是我的基准 package redisbenchmark import redis clients jedis
  • Spring Data Redis JedisConnectionException:流意外结束

    雷迪斯3 0 5Spring数据Redis 1 3 6绝地武士2 6 3 我们的 Web 应用程序通过 pub sub 从 Redis 接收数据 还以键 值对的形式在 Redis 上执行数据读 写 读 写发生在监听线程 独立监控线程和htt
  • 从redis中检索大数据集

    一台服务器上的应用程序查询另一台服务器上运行的 Redis 查询的结果数据集约为 250kzrangebyscore objects locations inf inf这在应用程序服务器上似乎需要 40 秒 当使用命令执行时redis cl
  • redis 阻塞直到 key 存在

    我是 Redis 新手 想知道是否有办法能够await get通过它的键来获取值 直到该键存在 最小代码 async def handler data await self fetch key async def fetch key ret
  • 如何测试我的 Redis 缓存是否正常工作?

    我已经安装了 django redis cache 和 redis py 我遵循了 Django 的缓存文档 据我所知 以下设置就是我所需要的 但我如何判断它是否正常工作 设置 py CACHES default BACKEND redis
  • 使用Redis从有限范围内生成唯一ID

    我有一些数据库项目 除了主键之外 还需要项目所属组的唯一索引 我们来调用属性nbr 以及将项目分组在一起并定义唯一范围的属性nbr 我们会打电话group This nbr必须在 1 N 范围内 并且may从外部源导入项目时进行设置 由于所
  • 如何在Redis中从hmset()切换到hset()?

    我收到弃用警告 即 Redis hmset 已弃用 请改用 Redis hset 但是 hset 采用第三个参数 我不知道是什么name应该是 info users 10 timestamp datetime utcnow strftime
  • 有没有办法让特定的key在集群模式下定位到特定的redis实例上?

    我想让我的多锁位于不同的redis实例上 我发现redission可以指定一个实例来执行命令 但是如果该命令与key相关 则指定的实例会将命令传输到另一个实例 你能给我一些建议吗 你可以 但这并不是微不足道的 首先 Redis 在键中使用大
  • 使用 Celery 通过 Gevent 进行实时、同步的外部 API 查询

    我正在开发一个 Web 应用程序 该应用程序将接收用户的请求 并且必须调用许多外部 API 来编写对该请求的答案 这可以直接从主 Web 线程使用 gevent 之类的东西来扇出请求来完成 或者 我在想 我可以将传入的请求放入队列中 并使用
  • redis dump.rdb / 保存小文件

    Context 我正在使用redis 数据库小于 100 MB 但是 我想进行每日备份 我也在 Ubuntu Server 12 04 上运行 当输入 redis cli save 我不知道 dump rdb 保存到哪里 因为 redis
  • Scala 使用的 Redis 客户端库建议

    我正在计划使用 Scala 中的 Redis 实例进行一些工作 并正在寻找有关使用哪些客户端库的建议 理想情况下 如果存在一个好的库 我希望有一个为 Scala 而不是 Java 设计的库 但如果现在这是更好的方法 那么仅使用 Java 客
  • 如何将“.csv”数据文件导入Redis数据库

    如何将 csv 数据文件导入 Redis 数据库 csv 文件中包含 id 时间 纬度 经度 列 您能否向我建议导入 CSV 文件并能够执行空间查询的最佳方法 这是一个非常广泛的问题 因为我们不知道您想要什么数据结构 您期望什么查询等等 为
  • Redis 队列工作程序在 utcparse 中崩溃

    我正在尝试按照以下教程获得基本的 rq 工作 https blog miguelgrinberg com post the flask mega tutorial part xxii background jobs https blog m

随机推荐