Redis系列16:聊聊布隆过滤器(原理篇)

redis,系列,聊聊,布隆,过滤器,原理篇 · 浏览次数 : 448

小编点评

**Redis 数据持久化** Redis 提供多种持久化机制,可以将数据持久化到不同的存储设备,包括本地文件、Redis Server 中的持久化文件、 Amazon S3 等。 **高可用** Redis 采用主从架构,其中一个主服务器负责存储数据,另一个从服务器负责提供读取数据的服务。如果主服务器失效,从服务器可以切换到主服务器上。 **Sentinel** Sentinel 是一个用于高可用 Redis 的监控工具,它可以监视 Redis 的健康状况并通知用户或其他服务器当出现问题时。 **Cluster 集群模式** Cluster 集群模式是一种可以运行多个 Redis 服务器的集群。这种模式可以提高系统性能和可用性,但它也需要一些额外的配置。 **高可用之 Sentinel** Sentinel 可以安装在 Redis 上,它可以监控 Redis 的健康状况并通知用户或其他服务器当出现问题时。 **Bloom Filter** Bloom Filter 是一个概率性数据结构,可用于判断一个元素是否存在于一个集合中。 Bloom Filter 使用二进制向量和一系列随机映射函数来实现去重功能。 **使用场景** Bloom Filter 可以用于以下场景: * 解决大流量下缓存穿透问题 * 过滤被屏蔽、拉黑、减少推荐的信息 **其他功能** 除了 Bloom Filter 之外,Redis 还支持许多其他功能,包括: * 客户端缓存 * Stream * List * Hash

正文

Redis系列1:深刻理解高性能Redis的本质
Redis系列2:数据持久化提高可用性
Redis系列3:高可用之主从架构
Redis系列4:高可用之Sentinel(哨兵模式)
Redis系列5:深入分析Cluster 集群模式
追求性能极致:Redis6.0的多线程模型
追求性能极致:客户端缓存带来的革命
Redis系列8:Bitmap实现亿万级数据计算
Redis系列9:Geo 类型赋能亿级地图位置计算
Redis系列10:HyperLogLog实现海量数据基数统计
Redis系列11:内存淘汰策略
Redis系列12:Redis 的事务机制
Redis系列13:分布式锁实现
Redis系列14:使用List实现消息队列
Redis系列15:使用Stream实现消息队列

1 Bloom Filter 介绍

布隆过滤器(Bloom Filter)是 Redis 4.0 版本提供的新功能,我们一般将它当做插件加载到 Redis 服务器中,给 Redis 提供强大的去重功能。
它是一种概率性数据结构,可用于判断一个元素是否存在于一个集合中。相比较之 Set 集合的去重功能,布隆过滤器空间上能节省 90% +,不足之处是去重率大约在 99% 左右,那就是有 1% 左右的误判率,这种误差是由布隆过滤器的自身结构决定的。

  • 优点:空间效率和查询时间都比一般的算法要好的多
  • 缺点:有一定的误识别率和删除困难

2 原理分析

布隆过滤器(Bloom Filter)是一个高空间利用率的概率性数据结构,由二进制向量(即位数组)和一系列随机映射函数(即哈希函数)两部分组成。
通过使用exists()来判断某个元素是否存在于自身结构中。当布隆过滤器判定某个值存在时,其实这个值只是有可能存在;当它说某个值不存在时,那这个值肯定不存在,这个误判概率大约在 1% 左右。
原理拆解如下:

  • 在一个很长的二进制向量和一系列随机映射函数的基础上,将元素哈希成不同的位置,每个位置对应二进制向量中的一个比特位。
  • 当加入一个元素时,采用 n 个相互独立的 Hash 函数计算key,然后将元素 Hash 映射的 n 个位置全部设置为 1。
  • 检测 key 是否存在,仍然用 Hash 函数计算出这 n 个位置,如果元素key 存在于集合中,则对应的位置为1,否则为0。
  • 如果n个位置均为1的话,可以确定元素key可能存在于集合中;如果有一个为0,那么元素的key一定不存在于集合中,下面会详细分析这句话。
  • 这种判断机制会存在误判的可能,但它以较小的空间代价和极简的时间复杂度来近似解决集合交、并、差等操作。

2.1 添加元素步骤

image
当使用布隆过滤器添加 key 时,会使用不同的 hash 函数对 key 存储的元素值进行哈希计算,从而会得到多个哈希值。根据哈希值计算出一个整数索引值,将该索引值与位数组长度做取余运算,最终得到一个位数组位置,并将该位置的值变为 1。每个 hash 函数都会计算出一个不同的位置,然后把数组中与之对应的位置变为 1。这边可能出现元素碰撞的情况,比如位置3,a元素和b元素的hash计算位置一致,所以出现了碰撞。

2.2 判定元素是否存在步骤

如果我们要判定一个元素是否存在,需要如下步骤:

  • 首先对给定元素key执行哈希计算,这样可以得到元素增加时的bit位数组位置
  • 判断这些位置是否都为 1,如果其中有一个为 0,那么说明元素不存在
  • 若全部位置都为 1,则说明元素有可能存在。

为啥说是可能存在呢,因为上面说过了,哈希函数出的结果会出现碰撞,所以布隆过滤器会存在误判。
image
如上图c,他的位置被其他元素的位置完全覆盖,即使c没有存储,对应位置上也被a和b的Hash函数设置为1,这时候就可能误判为c是有存储的。
有概率存在这样的 key,它们内容不同,但多次 Hash 后的 Hash 值都相同。

2.3 元素删除步骤

一般不会删除元素,我们上面说了,因为可能存在碰撞情况,所以也有可能存在误删除情况。
image
删除意味着需要将对应的 n 个 bits 位置设置为 0,其中有可能是其他元素对应的位。
比如图中的b删除之后,位置3的值也被设置为0,这样a也可能会被判定为不存在。

3 使用场景介绍

我们在遇到数据量大的时候,为了去重并避免大批量的重复计算,可以考虑使用 Bloom Filter 进行过滤。
具体常用的经典场景如下:

  • 解决大流量下缓存穿透的问题,参考笔者这篇《一次缓存雪崩的灾难复盘》。
  • 过滤被屏蔽、拉黑、减少推荐的信息,一般你在浏览抖音或者百度App的时候,看到不喜欢的会设置减少推荐、屏蔽此类信息等,都可以采用这种原理设计。
  • 各种名单过滤,使用布隆过滤器实现第一层的白名单或者黑名单过滤,可用于各种AB场景。

4 安装集成

如果是自己编译安装,可以从 github 下载,目前的latest 的 release 版本是 v2.4.5,下载地址如下:
https://github.com/RedisBloom/RedisBloom/releases/tag/v2.4.5
image

直接按照编译的方式进行安装:

# 解压文件:
tar -zxvf tar -zxvf RedisBloom-2.4.5.tar.gz
# 进入目录:
cd RedisBloom-2.4.5
# 执行编译命令,生成redisbloom.so 文件:
make
# 拷贝至指定目录:
cp redisbloom.so /usr/local/redis/RedisBloom-2.4.5/redisbloom.so

# 需要修改 redis.conf 文件,新增 loadmodule配置,并重启 Redis。
# 在redis配置文件里加入以下配置:
loadmodule /usr/local/redis/RedisBloom-2.4.5/redisbloom.so

# 配置完成后重启redis服务:
redis-server /usr/local/redis/RedisBloom-2.4.5/redis.conf

# 测试是否安装成功
127.0.0.1:6379> bf.add user brand
(integer) 1
127.0.0.1:6379> bf.exists user brand
(integer) 1

5 总结

大致说了布隆过滤器的原理和使用场景,下一篇我们来看看实战。

与Redis系列16:聊聊布隆过滤器(原理篇)相似的内容:

Redis系列16:聊聊布隆过滤器(原理篇)

[Redis系列1:深刻理解高性能Redis的本质](https://www.cnblogs.com/wzh2010/p/15886787.html "Redis系列1:深刻理解高性能Redis的本质") [Redis系列2:数据持久化提高可用性](https://www.cnblogs.com/w

redis系列02---缓存过期、穿透、击穿、雪崩

一、缓存过期 问题产生的原由: 内存空间有限,给缓存设置过期时间,但有些键值运气比较好,每次都没有被我的随机算法选中,每次都能幸免于难,这可不行,这些长时间过期的数据一直霸占着不少的内存空间! 解决方案: redis提供8种策略供应用程序选择,用于我遇到内存不足时该如何决策: * noevictio

[转帖]Redis系列(十五)、Redis6新特性之集群代理(Cluster Proxy)

在之前的文章中介绍了Redis6的集群搭建和原理,我们可以使用dummy和smart客户端连接集群,本篇介绍Redis6新增的一个功能:集群代理。客户端不需要知道集群中的具体节点个数和主从身份,可以直接通过代理访问集群,对于客户端来说通过集群代理访问的集群就和单机的Redis一样,因此也能解决很多集

[转帖]Redis系列(十六)、Redis6新特性之IO多线程

https://blog.csdn.net/wsdc0521/article/details/106766587 终于,Redis的多线程版本横空出世,大大提高了并发,本篇就带大家来看看什么是IO多线程,和我们理解的多线程有什么区别,与Memcached的多线程又有什么区别。 目录 介绍 为什么Re

[转帖]Redis系列(十七)、Redis中的内存淘汰策略和过期删除策略

我们知道Redis是分布式内存数据库,基于内存运行,可是有没有想过比较好的服务器内存也不过几百G,能存多少数据呢,当内存占用满了之后该怎么办呢?Redis的内存是否可以设置限制? 过期的key是怎么从内存中删除的?不要怕,本篇我们一起来看一下Redis的内存淘汰策略是如何释放内存的,以及过期的key

[转帖]Redis系列(十五)、Redis6新特性之集群代理(Cluster Proxy)

在之前的文章中介绍了Redis6的集群搭建和原理,我们可以使用dummy和smart客户端连接集群,本篇介绍Redis6新增的一个功能:集群代理。客户端不需要知道集群中的具体节点个数和主从身份,可以直接通过代理访问集群,对于客户端来说通过集群代理访问的集群就和单机的Redis一样,因此也能解决很多集

[转帖]【Redis系列】Redis发布版本历史及特性

目录 概述Redis2.6Redis2.8Redis3.0Redis3.2Redis4.0Redis5.0Redis6.0Redis7.0 概述 Redis 使用标准版本标记进行版本控制:major.minor.patchlevel。 偶数的版本号表示稳定的版本, 例如 1.2,2.0,2.2,2.

Redis系列8:Bitmap实现亿万级数据计算

Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5:深入分析Cluster 集群模式 追求性能极致:Redis6.0的多线程模型 追求性能极致:客户端缓

Redis系列9:Geo 类型赋能亿级地图位置计算

Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5:深入分析Cluster 集群模式 追求性能极致:Redis6.0的多线程模型 追求性能极致:客户端缓

Redis系列10:HyperLogLog实现海量数据基数统计

Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5:深入分析Cluster 集群模式 追求性能极致:Redis6.0的多线程模型 追求性能极致:客户端缓