【Redis】布隆过滤器原理与应用

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 【Redis】布隆过滤器原理与应用

布隆过滤器(Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。

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


原理


在谈到原理之前,我们先来看看布隆过滤器的数据结构,它是一个bit数组。如下图所示:

从图中看出,标有浅蓝色的bit位的值都被置为1,表示该数据已经映射上了。接着我们再把值“alibaba”和三个不同哈希函数生成的值:2、6、8映射到上面布隆过滤器中,它就会变为下图的样子:

很显然,它把之前映射的哈希值6覆盖了,这就是布隆过滤器是有误报率的一个因素。如果这时候,我们想拿一个未插入映射的值“tencent”查询它是否在上面布隆过滤器中存在。该怎么操作呢?首先,把值“tencent”用上面三个不同哈希函数生成三个哈希值分别是:2、4、6;再去布隆过滤器上找这三个值对应的bit位的值是否都是1,我们发现2和6都返回了1,而4返回0,说明值“tencent”没有做过映射,即不存在。实际上我们并没有事先做过此值的插入映射操作。这当然是正确的。


总结:布隆过滤器的原理是,当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组中的 K 个点(offset),把它们置为 1。检索时,我们只要看看这些点是不是都是 1 就(大约)知道集合中有没有它了:如果这些点有任何一个 0,则被检元素一定不在;如果都是 1,则被检元素很可能在。这就是布隆过滤器的基本思想。


简单来说就是准备一个长度为 m 的位数组并初始化所有元素为 0,用 k 个散列函数对元素进行 k 次散列运算跟 len(m)取余得到 k 个位置并将 m 中对应位置设置为 1。


SO:当我们搜索一个值的时候,若该值经过 K 个哈希函数运算后的任何一个索引位为 ”0“,那么该值肯定不在集合中。但如果所有哈希索引值均为 ”1“,则只能说该搜索的值可能存在集合中。


应用


在实际工作中,布隆过滤器常见的应用场景如下:


  • 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱;
  • Google Chrome 使用布隆过滤器识别恶意 URL;
  • Medium 使用布隆过滤器避免推荐给用户已经读过的文章;
  • Google BigTable,Apache HBbase 和 Apache Cassandra 使用布隆过滤器减少对不存在的行和列的查找。 除了上述的应用场景之外,布隆过滤器还有一个应用场景就是解决缓存穿透的问题。所谓的缓存穿透就是服务调用方每次都是查询不在缓存中的数据,这样每次服务调用都会到数据库中进行查询,如果这类请求比较多的话,就会导致数据库压力增大,这样缓存就失去了意义。
  • 解决缓存穿透

利用布隆过滤器我们可以预先把数据查询的主键,比如用户 ID 或文章 ID 缓存到过滤器中。当根据 ID 进行数据查询的时候,我们先判断该 ID 是否存在,若存在的话,则进行下一步处理。若不存在的话,直接返回,这样就不会触发后续的数据库查询。需要注意的是缓存穿透不能完全解决,我们只能将其控制在一个可以容忍的范围内。


实战


依赖:

<dependency>
   <groupId>com.google.guava</groupId>
   <artifactId>guava</artifactId>
   <version>28.0-jre</version>
</dependency>

在导入 Guava 库后,我们新建一个 BloomFilterDemo 类,在 main 方法中我们通过 BloomFilter.create 方法来创建一个布隆过滤器,接着我们初始化 1 百万条数据到过滤器中,然后在原有的基础上增加 10000 条数据并判断这些数据是否存在布隆过滤器中:

import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

public class BloomFilterDemo {
    public static void main(String[] args) {
        int total = 1000000; // 总数量
        BloomFilter<CharSequence> bf = 
          BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), total);
        // 初始化 1000000 条数据到过滤器中
        for (int i = 0; i < total; i++) {
            bf.put("" + i);
        }
        // 判断值是否存在过滤器中
        int count = 0;
        for (int i = 0; i < total + 10000; i++) {
            if (bf.mightContain("" + i)) {
                count++;
            }
        }
        System.out.println("已匹配数量 " + count);
    }
}

打印结果:

已匹配数量 1000309


很明显以上的输出结果已经出现了误报,因为相比预期的结果多了 309 个元素,误判率为:

309/(1000000 + 10000) * 100 ≈ 0.030594059405940593


如果要提高匹配精度的话,我们可以在创建布隆过滤器的时候设置误判率 fpp:

BloomFilter<CharSequence> bf 
    = BloomFilter.create(   Funnels.stringFunnel(Charsets.UTF_8), total, 0.0002 );

在 BloomFilter 内部,误判率 fpp 的默认值是 0.03:

// com/google/common/hash/BloomFilter.class 
public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions) {   return create(funnel, expectedInsertions, 0.03D); } 

在重新设置误判率为 0.0002 之后,我们重新运行程序,这时控制台会输出以下结果:

已匹配数量 1000003


通过观察以上的结果,可知误判率 fpp 的值越小,匹配的精度越高。当减少误判率 fpp 的值,需要的存储空间也越大,所以在实际使用过程中需要在误判率和存储空间之间做个权衡。


总结


本文主要介绍的布隆过滤器的概念和常见的应用场合,在实战部分我们演示了 Google 著名的 Guava 库所提供布隆过滤器(Bloom Filter)的基本使用,同时我们也介绍了布隆过滤器出现误报的原因及如何提高判断准确性。最后为了便于大家理解布隆过滤器,我们介绍了一个简易版的布隆过滤器 SimpleBloomFilter。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
8天前
|
运维 NoSQL Serverless
Serverless 应用引擎产品使用合集之需要配置什么才能够使用Redis
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
8天前
|
NoSQL 关系型数据库 Serverless
Serverless 应用引擎产品使用合集之连接RDS、Redis等数据库时,是否需要通过安全组来控制访问权限
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
9天前
|
运维 NoSQL Serverless
Serverless 应用引擎产品使用合集之函数计算里是否可以使用redis less
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
12天前
|
消息中间件 NoSQL Linux
详解Redis的主从同步原理
只不过在主节点中叫做master_repl_offset; 从节点也有一个偏移量叫做slave_repl_offset,用来记录从节点已经从主节点的repl_backlog_buffer中同步到的最新写指令的位置;
161 0
|
14天前
|
网络协议 NoSQL Redis
SMC-R 透明加速 TCP 技术,在 Redis 场景下的应用实践 | 干货推荐
SMC-R 作为一套与 TCP/IP 协议平行、向上兼容 socket 接口、底层使用 RDMA 完成共享内存通信的内核协议栈,其设计意图是为 TCP 应用提供透明的 RDMA 服务,同时保留了 TCP/IP 生态系统中的关键功能。
|
17天前
|
NoSQL Redis 数据库
【Redis从入门到入土】布隆过滤器简介、特点和原理
【6月更文挑战第1天】布隆过滤器是一种节省内存的不确定数据结构,用于判断元素是否可能在一个集合中。它由位数组和多个哈希函数组成,能快速插入和查询,但存在误判风险:可能存在假阳性(判断存在但实际不存在),但绝无假阴性(判断不存在则确实不存在)。适用于大规模数据的去重问题,如电话号码判断、安全网站链接检查、黑名单和白名单校验。其工作原理是通过多个哈希函数将元素映射到位数组中,添加时设置相应位置为1,查询时所有位置都为1则可能存在,有0则肯定不存在。由于哈希冲突,可能导致误判,且一旦添加元素无法删除,以避免影响其他元素。
27 4
|
1月前
|
存储 缓存 NoSQL
由菜鸟到大神,谈谈redis的概念、实战、原理、高级使用方法
【5月更文挑战第18天】Redis是一个开源的内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如字符串、哈希、列表、集合、有序集合等。
33 10
|
1月前
|
存储 NoSQL Redis
Redis数据结构精讲:选择与应用实战指南
Redis数据结构精讲:选择与应用实战指南
1194 1
|
1月前
|
存储 NoSQL 算法
深入浅出Redis(十一):Redis四种高级数据结构:Geosptial、Hypeloglog、Bitmap、Bloom Filter布隆过滤器
深入浅出Redis(十一):Redis四种高级数据结构:Geosptial、Hypeloglog、Bitmap、Bloom Filter布隆过滤器
|
1月前
|
负载均衡 NoSQL 关系型数据库
深入浅出Redis(六):Redis的主从架构与主从复制原理
深入浅出Redis(六):Redis的主从架构与主从复制原理