1. 简介

布隆过滤器是防止缓存穿透的方案之一。布隆过滤器主要是解决大规模数据下不需要精确过滤的业务场景,如检查垃圾邮件地址,爬虫URL地址去重, 解决缓存穿透问题等。

布隆过滤器:在一个存在一定数量的集合中过滤一个对应的元素,判断该元素是否一定不在集合中或者可能在集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难

想详细了解的,可以查看我的另一篇博客Redis-缓存穿透/击穿/雪崩

2. guava 实现

google的guava工具类已经帮我们造好了轮子,通过实例来感受一下。

2.1 导入依赖

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

2.2 BloomFilterTest

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import lombok.extern.slf4j.Slf4j; /**
* 布隆过滤器简单实现
* @author ludangxin
* @date 2021/8/16
*/
@Slf4j
public class BloomFilterTest {
/**
* 预计要插入元素个数
*/
private static final int SIZE = 1000000;
/**
* 误判率
*/
private static final double FPP = 0.01;
/**
* 布隆过滤器
*/
private static final BloomFilter<Integer> BLOOMFILTER = BloomFilter.create(Funnels.integerFunnel(), SIZE, FPP); public static void main(String[] args) {
//插入数据
for (int i = 0; i < 1000000; i++) {
BLOOMFILTER.put(i);
}
int count = 0;
// 过滤判断
for (int i = 1000000; i < 3000000; i++) {
if (BLOOMFILTER.mightContain(i)) {
count++;
log.info(i + "误判了");
}
}
log.info("总共的误判数:" + count);
}
}

2.3 启动测试

如上代码,我们设置了0.01的误差,过滤判断时从1000000到3000000,误判了2 * 20000000 ≈ 20339 符合预期。

.....
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999004误判了
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999045误判了
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999219误判了
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999699误判了
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999753误判了
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999838误判了
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999923误判了
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999928误判了
21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 总共的误判数:20339

2.4 小节

guava的工具包虽然好用,但是数据集是存储在jvm中的,分布式环境下依然没法使用。

3. redisson 实现

3.1 导入依赖

<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.16.1</version>
</dependency>

3.2 BloomFilterWithRedisson

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; /**
* redisson 布隆过滤器实现
*
* @author ludangxin
* @date 2021/8/16
*/
@Slf4j
@RestController
@RequestMapping("bloomFilter")
@RequiredArgsConstructor
public class BloomFilterWithRedisson {
private final RedissonClient redissonClient; /**
* 预计要插入元素个数
*/
private static final long SIZE = 1000000L;
/**
* 误判率
*/
private static final double FPP = 0.01; /**
* 自定义布隆过滤器的 key
*/
private static final String BLOOM_FILTER_KEY = "bloomFilter"; /**
* 向布隆过滤器中添加数据, 模拟向布隆过滤器中添加10亿个数据
*/
@GetMapping
public void filter() {
// 获取布隆过滤器
RBloomFilter<Integer> bloomFilter = redissonClient.getBloomFilter(BLOOM_FILTER_KEY);
// 初始化,容量为100万, 误判率为0.01
bloomFilter.tryInit(SIZE, FPP);
// 模拟向布隆过滤器中添加100万个数据
for (int i = 0; i < SIZE; i++) {
bloomFilter.add(i);
}
int count = 0;
// 过滤判断
for (int i = 1000000; i < 3000000; i++) {
if (bloomFilter.contains(i)) {
count++;
log.info(i + "误判了");
}
}
log.info("size:" + bloomFilter.getSize());
log.info("总共的误判数:" + count);
}
}

3.3 启动测试

由于机器性能有限,又是单机环境,所以程序没有跑完。

但由此也可以看出,基于redis的布隆过滤器虽然解决了分布式问题,但是性能和guava bloomfilter没法比。

Redisson实战-BloomFilter的更多相关文章

  1. 别再用 Redis List 实现消息队列了,Stream 专为队列而生

    上回说到使用 Redis 的 List 实现消息队列有很多局限性,比如: 没有良好的 ACK 机制: 没有 ConsumerGroup 消费组概念: 消息堆积. List 是线性结构,想要查询指定数据 ...

  2. Redis HyperLogLog 是什么?这些场景使用它,让我枪出如龙,一笑破苍穹

    在移动互联网的业务场景中,数据量很大,我们需要保存这样的信息:一个 key 关联了一个数据集合,同时对这个数据集合做统计. 比如: 统计一个 APP 的日活.月活数: 统计一个页面的每天被多少个不同账 ...

  3. Redisson 分布式锁实战与 watch dog 机制解读

    Redisson 分布式锁实战与 watch dog 机制解读 目录 Redisson 分布式锁实战与 watch dog 机制解读 背景 普通的 Redis 分布式锁的缺陷 Redisson 提供的 ...

  4. Redis实战篇

    Redis实战篇 1 Redis 客户端 1.1 客户端通信 原理 客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 . 客户端和服务器发送的命令或数据一律以 \r\n ...

  5. redis(7)--redis应用实战

    问题1:哨兵模式下客户端应该连接哪个redis-server? 问题2:集群模式下为什么会有MOVED error Redis Java客户端介绍 已有的客户端支持 Redis Java客户端有很多的 ...

  6. 硬核 | Redis 布隆(Bloom Filter)过滤器原理与实战

    在Redis 缓存击穿(失效).缓存穿透.缓存雪崩怎么解决?中我们说到可以使用布隆过滤器避免「缓存穿透」. 码哥,布隆过滤器还能在哪些场景使用呀? 比如我们使用「码哥跳动」开发的「明日头条」APP 看 ...

  7. (转)国内外三个不同领域巨头分享的Redis实战经验及使用场景

    随着应用对高性能需求的增加,NoSQL逐渐在各大名企的系统架构中生根发芽.这里我们将为大家分享社交巨头新浪微博.传媒巨头Viacom及图片分享领域佼佼者Pinterest带来的Redis实践,首先我们 ...

  8. 【原】实战-Java如何使用Redis

    实战-Java如何使用Redis Redis的Client支持的语言非常丰富,如下: ActionScript Bash C C# C++ Clojure Common Lisp Crystal D ...

  9. Hbase 设计与开发实战

    Hbase 概述 大数据及 NoSQL 的前世今生 传统的关系型数据库处理方式是基于全面的 ACID 保证,遵循 SQL92 的标准表设计模式(范式)和数据类型,基于 SQL 语言的 DML 数据交互 ...

随机推荐

  1. Redis 底层数据结构之整数集合

    文章参考:<Redis 设计与实现>黄建宏 整数集合 整数集合时集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合数量不多时,就会使用整数集合 typedef struct i ...

  2. AcWing 102. 最佳牛围栏

    农夫约翰的农场由 N 块田地组成,每块地里都有一定数量的牛,其数量不会少于1头,也不会超过2000头. 约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大 ...

  3. 暑假自学java第五天

    关于测试类的问题: 单独创建一个包存放测试类,如com.test 首先要构建路径添加测试类的相关类库,方法是项目右键,buld path->config buld path->librar ...

  4. 一文看懂HTTPS、证书机构(CA)、证书、数字签名、私钥、公钥(转)

    说到https,我们就不得不说tls/ssl,那说到tls/ssl,我们就不得不说证书机构(CA).证书.数字签名.私钥.公钥.对称加密.非对称加密.这些到底有什么用呢,正所谓存在即合理,这篇文章我就 ...

  5. pxe+kickstart部署多个版本的Linux操作系统(下)---实践篇

        我们在企业运维环境中,难免会遇到使用多个Linux操作系统的情况,如果每天都需要安装不同版本的Linux系统的话,那么使用Kickstart只能安装一种版本的Linux系统的方法则显得有些捉襟 ...

  6. c语言:getch() getchar()

    1.getchar();从键盘读取一个字符并输出,该函数的返回值是输入第一个字符的ASCII码:若用户输入的是一连串字符,函数直到用户输入回车时结束,输入的字符连同回车一起存入键盘缓冲区.若程序中有后 ...

  7. Jmeter之事务控制器

    性能测试的结果统计时我们一定会关注TPS,TPS代表的是每秒事务数,每个事务对应的是我们的请求.虽然JMeter能够帮我们把每个请求统计成一个事务,但有时候我们希望把多个操作统计成一个事务,JMete ...

  8. 团队开发day07

    开始整合项目,测试登录,注册,搜索功能, 在安卓中数据处理存在个别错误,功能逻辑有个别不正确 进行修改和完善,添加二次确认退出

  9. LeetCode 847. Shortest Path Visiting All Nodes

    题目链接:https://leetcode.com/problems/shortest-path-visiting-all-nodes/ 题意:已知一条无向图,问经过所有点的最短路径是多长,边权都为1 ...

  10. Python+Scrapy+Crawlspider 爬取数据且存入MySQL数据库

    1.Scrapy使用流程 1-1.使用Terminal终端创建工程,输入指令:scrapy startproject ProName 1-2.进入工程目录:cd ProName 1-3.创建爬虫文件( ...