基于Redisson的Redis结合布隆过滤器使用
一、场景
- 缓存穿透问题
一般情况下,先查询Redis缓存,如果Redis中没有,再查询MySQL。当某一时刻访问redis的大量key都在redis中不存在时,所有查询都要访问数据库,造成数据库压力顿时上升,这就是缓存穿透。八股文背多了都知道:在Redis前面添加一层布隆过滤器,请求先在布隆过滤器中判断,如果布隆过滤器不存在时,直接返回,不再访问Redis和MySQL。如果布隆过滤器中存在时,再访问Redis,再访问数据库。完美解决缓存穿透问题。说白了:布隆过滤器就是redis的缓存

除此之外还有以下场景:
- 黑名单 :如果黑名单非常大,上千万了,存放起来很耗费空间,在布隆过滤器中实现黑名单功能,是一个很好的选择。
- 网页爬虫对URL的去重,避免爬取相同的URL地址
二、布隆过滤器
- 布隆过滤器BloomFilter是什么
布隆过滤器BloomFilter是一种专门用来解决去重问题的高级数据结果。实质就是一个大型位数组和几个不同的无偏hash函数,无偏表示分布均匀。由一个初值为零的bit数组和多个哈希函数组成,用来判断某个数据是否存在,它和HyperLogLog一样,不是那么的精准,存在一定的误判概率。
- 布隆过滤器BloomFilter能干嘛?

-
高效地插入和查询,占用空间少,返回的结果是不确定的,
一个元素如果判断结果为存在,它不一定存在;不存在时,一定不存在。 查询某个变量的时候我们只要看看这些点是不是都是 1, 就可以大概率知道集合中有没有它了。如果这些点, 有任何一个为零则被查询变量一定不在, 如果都是 1,则被查询变量很 可能存在。 为什么说是可能存在,而不是一定存在呢?那是因为映射函数本身就是散列函数,散列函数是会有碰撞的。 -
布隆过滤器BloomFilter只能添加元素,不能删除元素。这和上面提到的hashcode判定原理是一样的,相同hashcode的字符串会存储在一个index,删除时,是将某个index移除,此时,就可能移除拥有相同hashcode的不同字符串
三、实现原理和数据结构
- 初始化
布隆过滤器 本质上 是由长度为 m 的位向量或位列表(仅包含 0 或 1 位值的列表)组成,最初所有的值均设置为

- 添加
当我们向布隆过滤器中添加数据时,为了尽量地址不冲突, 会使用多个 hash 函数对 key 进行运算 ,算得一个下标索引值,然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就完成了 add 操作。 例如,我们添加一个字符串wmyskxz:

- 判断是否存在
向布隆过滤器查询某个key是否存在时,先把这个 key 通过相同的多个 hash 函数进行运算 ,查看对应的位置是否都为 1, 只要有一个位为 0,那么说明布隆过滤器中这个 key 不存在; 如果这几个位置全都是 1,那么说明极有可能存在; 因为这些位置的 1 可能是因为其他的 key 存在导致的,也就是前面说过的hash冲突。
例子:我们在 add 了字符串wmyskxz数据之后,很明显下面1/3/5 这几个位置的 1 是因为第一次添加的 wmyskxz 而导致的; 此时我们查询一个没添加过的不存在的字符串inexistent-key,它有可能计算后坑位也是1/3/5 ,这就是误判了。

- 误判率,为什么不能删除元素?
布隆过滤器的误判是指多个输入经过哈希之后在相同的bit位置1了,这样就无法判断究竟是哪个输入产生的, 因此误判的根源在于相同的 bit 位被多次映射且置 1。 这种情况也造成了布隆过滤器的删除问题,因为布隆过滤器的每一个 bit 并不是独占的,很有可能多个元素 共享了某一位 。 如果我们直接删除这一位的话,会影响其他的元素。
- 如何解决不能删除
- 布谷鸟过滤器
为了解决布隆过滤器不能删除元素的问题 ,布谷鸟过滤器横空出世。论文《Cuckoo Filter:Better Than Bloom》
作者将布谷鸟过滤器和布隆过滤器进行了深入的对比。相比布谷鸟过滤器而言布隆过滤器有以下不足: 查询性能弱、空间利用效率低、不支持反向操作(删除)以及不支持计数
- 常用命令
在Redis中,布隆过滤器有两个基本命令,分别是:
- bf.add:添加元素到布隆过滤器中,类似于集合的sadd命令,不过bf.add命令只能一次添加一个元素,
如果想一次添加多个元素,可以使用bf.madd命令。- bf.exists:判断某个元素是否在过滤器中,类似于集合的sismember命令,不过bf.exists命令只能一次查询一个元素,
如果想一次查询多个元素,可以使用bf.mexists命令。
四、Redis使用布隆过滤器
- redis版本:推荐版本6.x,最低4.x版本
- 下载布隆过滤器插件(版本自选)
wget https://github.com/RedisLabsModules/rebloom/archive/v2.2.6.tar.gz
- 解压,编译,得到.so
- tar -zxvf v2.2.6.tar.gz
- cd RedisBloom-2.2.6/
- make
- Redis配置文件修改
在redis.conf配置文件中加入如RedisBloom的redisbloom.so文件的地址
loadmodule /usr/local/soft/RedisBloom-2.2.6/redisbloom.so
如果是集群则每个配置文件中都需要加入redisbloom.so文件的地址

- 添加完成后需要重启redis
- 集成布隆过滤器的redis项目:
Rebloom插件布隆过滤器,有原生镜像可以直接使用
五、代码层面调用(java)
- 基于redisson实现
package com.ruoyi.demo;import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;import java.util.concurrent.TimeUnit;public class RedissonBloomFilterDemo {public static final int _1W = 10000;//布隆过滤器里预计要插入多少数据public static int size = 100 * _1W;//误判率,它越小误判的个数也就越少public static double fpp = 0.03;static RedissonClient redissonClient = null;//jedisstatic RBloomFilter rBloomFilter = null;//redis版内置的布隆过滤器static {Config config = new Config();config.useSingleServer().setAddress("redis://192.168.1.8:6379").setPassword("cxm199610133914").setDatabase(2);//构造redissonredissonClient = Redisson.create(config);//通过redisson构造rBloomFilterrBloomFilter = redissonClient.getBloomFilter("phoneListBloomFilter",new StringCodec());rBloomFilter.tryInit(size,fpp);// 1测试 布隆过滤器有+redis有rBloomFilter.add("10086");redissonClient.getBucket("10086",new StringCodec()).set("chinamobile10086");// 2测试 布隆过滤器有+redis无rBloomFilter.add("10087");//3 测试 ,布隆过滤器无+redis无}private static String getPhoneListById(String IDNumber) {String result = null;if (IDNumber == null) {return null;}//1 先去布隆过滤器里面查询if (rBloomFilter.contains(IDNumber)) {//2 布隆过滤器里有,再去redis里面查询RBucket<String> rBucket = redissonClient.getBucket(IDNumber, new StringCodec());result = rBucket.get();if(result != null) {return "i come from redis: "+result;}else{result = getPhoneListByMySQL(IDNumber);if (result == null) {return null;}// 重新将数据更新回redisredissonClient.getBucket(IDNumber, new StringCodec()).set(result);}return "i come from mysql: "+result;}return result;}private static String getPhoneListByMySQL(String IDNumber) {return "chinamobile"+IDNumber;}public static void main(String[] args) {//String phoneListById = getPhoneListById("10086");//String phoneListById = getPhoneListById("10087"); //请测试执行2次String phoneListById = getPhoneListById("10088");System.out.println("------查询出来的结果: "+phoneListById);//暂停几秒钟线程try {TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e) {e.printStackTrace();}redissonClient.shutdown();}
}
参考文章
参考文章
相关文章:
基于Redisson的Redis结合布隆过滤器使用
一、场景 缓存穿透问题 一般情况下,先查询Redis缓存,如果Redis中没有,再查询MySQL。当某一时刻访问redis的大量key都在redis中不存在时,所有查询都要访问数据库,造成数据库压力顿时上升,这就是缓存穿透。…...
BrowserRouter刷新404解决方案
1、本地开发环境 在js脚本命令里加上 --history-api-fallback "scripts": {"serve": "webpack serve --config webpack.dev.js --history-api-fallback" }2、生产环境,可以修改 nglnx 配置: server {listen XXXX; //端口号…...
解决appium-doctor报opencv4nodejs cannot be found
一、下载cmake 在CMake官网下载:cmake-3.6.1-win64-x64.msi 二、安装cmake cmake安装过程 在安装时要选择勾选为所有用户添加CMake环境变量 三、检查cmake安装 重新管理员打开dos系统cmd命令提示符,输入cmake -version cmake -version四、安装opencv4no…...
安卓通过adb pull和adb push 手机与电脑之间传输文件
1.可以参考这篇文章 https://www.cnblogs.com/hhddcpp/p/4247923.html2.根据上面的文章,我做了如下修改 //设置/system为可读写: adb remount //复制手机中的文件到电脑中。需要在电脑中新建一个文件夹,我新建的文件夹为ce文件夹 adb pull …...
java常用的lambda表达式总结
一、概述 lambda表达式是JDK8中的一个新特性,对某些匿名内部类进行简化,是函数式编程; 二、基本格式 (参数列表)->{方法体代码} 三、Stream流 是jdk8中的新特性,将数据以流的形式进行操作 三、常用方法解析 3.1、准备工作 …...
分布式应用之zookeeper集群+消息队列Kafka
一、zookeeper集群的相关知识 1.zookeeper的概念 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能…...
GStreamer学习笔记(四)
Time management 仅当管道处于PLAYING状态时,可以刷新屏幕。如果不在PLAYING状态,什么都不做,因为大多数查询都会失败。 函数与知识点 GstClockTime 说明:所需的超时时间必须以GstClockTime的形式指定。即以纳秒(ns…...
DBeaver连接华为高斯数据库 DBeaver连接Gaussdb数据库 DBeaver connect Gaussdb
DBeaver连接华为高斯数据库 DBeaver连接Gaussdb数据库 DBeaver connect Gaussdb 一、概述 华为GaussDB出来已经有一段时间,最近工作中刚到Gauss数据库。作为coder,那么如何通过可视化工具来操作Gauss呢? 本文将记录使用免费、开源的DBeaver来…...
.net core 2.1 简单部署IIS运行
netcore的项目不像netFramework那么方便部署到iis还是要费点功夫的 比如我想把这个netcore2.1的项目部署到iis并运行: 按照步骤走: 一、确认自己的netcore环境 1、需要安装下面3个环境包(如果电脑已安装请忽略) 检查是否安装cmd命令:cmd&…...
提高视觉检测系统稳定性的隐藏办法——10G高速图像采集卡
提高视觉检测系统稳定性的隐藏办法——10G高速图像采集卡 目前,随着我国各方面配套基础设施建设的完善,企业技术、资金的积累,各行各业积极探索和大胆的尝试机器视觉技术,实现工业自动化、智能化。在机器视觉系统的使用过程中&am…...
注解方式实现数据库字段加密与解密
目录 前言实现步骤定义注解加密工具类定义mybatis拦截器 总结 前言 一些敏感信息存入数据需要进行加密处理,比如电话号码,身份证号码等,从数据库取出到前端展示时需要解密,如果分别在存入取出时去做处理,会很繁锁&…...
C\C++ 使用socket判断ip是否能连通
文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan 简介: 使用socket判断ip是否能联通 效果: 代码: #include <iostream> #include <cstdlib> #include <cstdio> #include &…...
数学建模-相关系数
excel基本操作:ctrl右,ctrl左,ctrlshift下/右,ctrlshift空格 题目里有数据,给出描述性统计是比较好的习惯 excel描述性统计:数据-数据分析-描述统计 MATLAB要做散点图C62个 SPSS可以直接画出两两之间的散…...
Ubuntu下安装、配置及重装CUDA教程
安装CUDA 前往Nvidia CUDA Tools官网选择对应的架构和版本下载CUDA 以如下架构和版本为例: 查看显卡驱动 nvidia-smi如果显卡驱动已经装了,那么在CUDA安装过程中不用再勾选安装driver 下载并安装CUDA wget https://developer.download.nvidia.co…...
自学网络安全(黑客)为什么火了?
网安专业从始至终都是需要学习的,大学是无法培养出合格的网安人才的。这就是为啥每年网安专业毕业生并不少,而真正从事网安岗位的人,寥寥无几的根本原因。 如果将来打算从事网安岗位,那么不断学习是你唯一的途径。 网络安全为什…...
Android S 修改关于手机的logo
1.让图片加载生效 frameworks/base/packages/SettingsLib/LayoutPreference/res/layout/preference_about_phone.xml <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android" android:id"id/entity_header" style"…...
Mysql 备份与还原
目录 一、数据备份的重要性 二、数据库备份类型 2.1 物理备份 2.2 逻辑备份 三、常见的备份方法 3.1 物理冷备 3.2 专用备份工具 mysqldump 或 mysqlhotcopy 3.3 启用二进制日志进行增量备份 3.4 第三方工具备份 四、MySQL完全备份 五、数据库完全备份分类…...
Cadence PCB 仿真Model Integrity专题
🏡《总目录》 🏡《宝典目录》 目录 1,内容概述2,内容目录 1,内容概述 本专题详细介绍Cadence的仿真建模工具 Model Integrity。 2,内容目录 Cadence PCB仿真 Model Integrity 功能详述与启动方法图文教…...
记一次阿里云被挖矿处理记录
摘要 莫名其妙的服务器就被攻击了,又被薅了羊毛,当做免费的挖矿劳动力了。 一、起因 上班(摸鱼)好好的,突然收到一条阿里云的推送短信,不看不知道,两台服务器被拉去作为苦力,挖矿去…...
Linux系统使用(超详细)
目录 Linux操作系统简介 Linux和windows区别 Linux常见命令 Linux目录结构 Linux命令提示符 常用命令 ls cd pwd touch cat echo mkdir rm cp mv vim vim的基本使用 grep netstat Linux面试题 Linux操作系统简介 Linux操作系统是和windows操作系统是并列…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...

