Redis-布隆过滤器解决穿透详解

本文已收录于专栏
《中间件合集》

目录

  • 背景介绍
  • 概念说明
  • 原理说明
  • 解决穿透
  • 安装使用
    • 安装过程
      • Redis为普通安装的配置方式
      • Redis为Docker镜像安装的配置方式
    • 具体使用
      • 控制台操作命令说明
      • Spring Boot集成布隆过滤器
  • 总结提升

背景介绍

  布隆过滤器可以帮助我们解决Redis缓存雪崩的问题,那什么是布隆过滤器、布隆过滤器又是如何使用如何解决缓存雪崩的问题的,让我们带着这一系列的问题去详细了解布隆过滤器。

概念说明

  布隆过滤器是一种用于快速判断一个元素是否属于一个集合的数据结构。它通常用于大规模数据集合中,可以快速判断一个元素是否可能存在于集合中,但不能确定一定存在。布隆过滤器的主要优点是占用内存少、查询速度快,并且可以容忍一定的误判率。

原理说明

  布隆过滤器由一个位数组和多个哈希函数组成。位数组通常初始化为0,哈希函数用于将元素映射到位数组中的多个位置。当一个元素被加入到布隆过滤器中时,它会被哈希函数映射到位数组的多个位置,然后将这些位置的值设为1。当查询一个元素是否存在于布隆过滤器中时,哈希函数会将元素映射到位数组的多个位置,然后检查这些位置的值是否都为1,如果有一个位置的值为0,则可以确定元素一定不存在于集合中,如果所有位置的值都为1,则元素可能存在于集合中。
  布隆过滤器的误判率取决于位数组的大小和哈希函数的数量。通常情况下,误判率随着位数组大小的增加而减小,但会占用更多的内存。因此,使用布隆过滤器时需要根据实际情况权衡误判率和内存占用。
在这里插入图片描述

解决穿透

  我们还可以在存储和缓存之前,加⼀个布隆过滤器,做⼀层过滤。布隆过滤器⾥会保存数据是否存在,如果判断数据不存在,就不会访问存储。
在这里插入图片描述

安装使用

安装过程

Redis为普通安装的配置方式

1、下载布隆过滤器这个插件

wget https://github.com/RedisLabsModules/rebloom/archive/v2.2.6.tar.gz

2、解压文件

tar -zxvf v2.2.6.tar.gz

在这里插入图片描述
3、编辑插件

# 到RedisBloom对应目录
cd /usr/local/redis/RedisBloom-2.2.6
# 编译插件
make

4、Redis集成RedisBloom插件

# vim查看redis.conf
vim /usr/local/redis/config/redis.conf
# 在文件后面添加如下配置
loadmodule /usr/local/redis/RedisBloom-2.2.6/redisbloom.so

在这里插入图片描述
5、配置完之后重启Redis即可。

Redis为Docker镜像安装的配置方式

1、创建文件夹以及配置文件,用于挂在redis启动的后容器中的文件,方便我们在容器外部操作redis的配置

mkdir data  ##创建文件夹
touch redis.conf  ## 创建文件

2、在我们创建的redis.conf文件中添加一行配置loadmodule /data/RedisBloom-2.2.6/redisbloom.so
在这里插入图片描述
3、随后直接使用dokcer run命令进行启动

docker run -p 6379:6379 --name redis -v /root/redis/data:/data -v 
/root/redis/redis.conf:/etc/redis/redis.conf --restart=always 
--network host  -d redis:5.0.7 redis-server /etc/redis/redis.conf

这个命令是用于在 Docker 中运行 Redis 容器,并进行一些配置。下面是对每个参数的解释:

  • -p 6379:6379: 将 Docker 容器的端口 6379 映射到主机的端口 6379,以便可以从主机访问 Redis 服务。
  • –name redis: 指定容器的名称为 “redis”。
  • -v /root/redis/data:/data: 将主机的 /root/redis/data 目录挂载到容器的 /data 目录,用于持久化保存 Redis 数据。
  • -v /root/redis/redis.conf:/etc/redis/redis.conf: 将主机的 /root/redis/redis.conf 配置文件挂载到容器的 /etc/redis/redis.conf,使用该配置文件作为 Redis 的配置。
  • –restart=always: 设置容器在退出时自动重新启动。
  • –network host: 使用主机网络模式,容器将共享主机的网络栈。
  • -d: 在后台运行容器。
  • redis:5.0.7: 指定使用的 Redis 镜像及其版本号。
  • redis-server /etc/redis/redis.conf: 在容器中执行的命令,即启动 Redis 服务器,并使用指定的配置文件。

执行上述操作redis容器如果启动没有问题那么我们的布隆过滤器的插件和redis都安装并启动成功了,如果没有启动成功可以通过docker logs 查看一下redis的启动过程中出现什么问题。

具体使用

控制台操作命令说明

  • BF.ADD:向布隆过滤器中添加一个元素。
	BF.ADD <key> <item>
  • BF.EXISTS:检查一个元素是否存在于布隆过滤器中。
	BF.EXISTS <key> <item>

-BF.MADD:向布隆过滤器中批量添加多个元素。

	BF.MADD <key> <item> [item ...]
  • BF.MEXISTS:批量检查多个元素是否存在于布隆过滤器中。
	BF.MEXISTS <key> <item> [item ...]
  • BF.INFO:获取布隆过滤器的信息,包括容量、误判率等。
	BF.INFO <key>
  • BF.RESERVE:创建一个新的布隆过滤器,并指定容量和误判率。
	BF.RESERVE <key> <error_rate> <capacity>
  • BF.COUNT:统计布隆过滤器中已添加的元素数量。
	BF.COUNT <key>

  给user过滤器添加一个元素,如果我们没有添加创建布隆过滤器,系统会给我们创建一个,其中布隆过滤器的容量为100,判错率为0.01这是布隆过滤器的默认配置,我们可以在创建布隆过滤器的时候进行修改。
在这里插入图片描述

Spring Boot集成布隆过滤器

1、引入依赖:这里使用的redis的过滤器所以用到的依赖直接使用的spring-data-redis这个就可以了。

        <!--redis的依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

2、布隆过滤器的工具类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;@Component
public class RedisBloomUtil {@Autowiredprivate RedisTemplate redisTemplate;// 初始化一个布隆过滤器public Boolean tryInitBloomFilter(String key, long expectedInsertions, double falseProbability) {Boolean keyExist = redisTemplate.hasKey(key);if(keyExist) {return false;}RedisScript<Boolean> script = new DefaultRedisScript<>(bloomInitLua(), Boolean.class);RedisSerializer stringSerializer = redisTemplate.getStringSerializer();redisTemplate.execute(script, stringSerializer, stringSerializer, Collections.singletonList(key), falseProbability+"", expectedInsertions+"");return true;}// 添加元素public Boolean addInBloomFilter(String key, Object arg) {RedisScript<Boolean> script = new DefaultRedisScript<>(addInBloomLua(), Boolean.class);return (Boolean) redisTemplate.execute(script, Collections.singletonList(key), arg);}@Transactional// 批量添加元素public Boolean batchAddInBloomFilter(String key, Object... args) {RedisScript<Boolean> script = new DefaultRedisScript<>(batchAddInBloomLua(), Boolean.class);return (Boolean) redisTemplate.execute(script, Collections.singletonList(key), args);}// 查看某个元素是否是存在public Boolean existInBloomFilter(String key, Object arg) {RedisScript<Boolean> script = new DefaultRedisScript<>(existInBloomLua(), Boolean.class);return (Boolean) redisTemplate.execute(script, Collections.singletonList(key), arg);}// 批量查看元素是否存在public List batchExistInBloomFilter(String key, Object... args) {RedisScript<List> script = new DefaultRedisScript(batchExistInBloomLua(), List.class);List<Long> results = (List) redisTemplate.execute(script, Collections.singletonList(key), args);List<Boolean> booleanList = results.stream().map(res -> res == 1 ? true : false).collect(Collectors.toList());return booleanList;}private String bloomInitLua() {return "redis.call('bf.reserve', KEYS[1], ARGV[1], ARGV[2])";}private String addInBloomLua() {return "return redis.call('bf.add', KEYS[1], ARGV[1])";}private String batchAddInBloomLua() {StringBuilder sb = new StringBuilder();sb.append("for index, arg in pairs(ARGV)").append("\r\n");sb.append("do").append("\r\n");sb.append("redis.call('bf.add', KEYS[1], arg)").append("\r\n");sb.append("end").append("\r\n");sb.append("return true");return sb.toString();}private String existInBloomLua() {return "return redis.call('bf.exists', KEYS[1], ARGV[1])";}private String batchExistInBloomLua() {StringBuilder sb = new StringBuilder();sb.append("local results = {}").append("\r\n");sb.append("for index, arg in pairs(ARGV)").append("\r\n");sb.append("do").append("\r\n");sb.append("local exist = redis.call('bf.exists', KEYS[1], arg)").append("\r\n");sb.append("table.insert(results, exist)").append("\r\n");sb.append("end").append("\r\n");sb.append("return results;");return sb.toString();}
}

总结提升

  布隆过滤器适用于需要快速判断一个元素是否可能存在于集合中的场景,例如网络爬虫中的去重、缓存中的数据判断等。但需要注意的是,布隆过滤器无法删除元素,也无法准确地判断一个元素是否存在于集合中,因此在一些场景下可能会产生误判。

🎯 此文章对你有用的话记得留言+点赞+收藏哦🎯

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/667609.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Fink CDC数据同步(四)Mysql数据同步到Kafka

依赖项 将下列依赖包放在flink/lib flink-sql-connector-kafka-1.16.2 创建映射表 创建MySQL映射表 CREATE TABLE if not exists mysql_user (id int,name STRING,birth STRING,gender STRING,PRIMARY KEY (id) NOT ENFORCED ) WITH (connector mysql-cdc,hostn…

算法学习打卡day47|单调栈系列题目

单调栈题目思路 通常是一维数组&#xff0c;要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置&#xff0c;此时我们就要想到可以用单调栈了。时间复杂度为O(n)。单调栈的本质是空间换时间&#xff0c;因为在遍历的过程中需要用一个栈来记录右边第一个比当前元…

电脑文件误删除怎么办?8个恢复软件解决电脑磁盘数据可能的误删

您是否刚刚发现您的电脑磁盘数据丢失了&#xff1f;不要绝望&#xff01;无论分区是否损坏、意外格式化或配置错误&#xff0c;存储在其上的文件都不一定会丢失到数字深渊。 我们已经卷起袖子&#xff0c;深入研究电脑分区恢复软件的广阔领域&#xff0c;为您带来一系列最有效…

如何标准化地快速编辑文档

介绍个公文类的文档技巧吧&#xff0c;尤其在国企、机关、有ISO管理体系内控要求的会议记录、公文写作等&#xff0c;要求大同小异&#xff0c;一般都是中规中矩的【GB/T 9704—2012】&#xff0c;其实国标本身就是经过长期检验&#xff0c;证明是最规范合理&#xff0c;阅读效…

深度学习介绍

对于具备完善业务逻辑的任务&#xff0c;大多数情况下&#xff0c;正常的人都可以给出一个符合业务逻辑的应用程序。但是对于一些包含超过人类所能考虑到的逻辑的任务&#xff0c;例如面对如下任务&#xff1a; 编写一个应用程序&#xff0c;接受地理信息、卫星图像和一些历史…

python爬虫代码示例:爬取京东详情页图片【京东API接口】

一、Requests请求示例【京东API接口】 爬虫爬取网页内容首先要获取网页的内容&#xff0c;通过requests库进行获取。 安装 pip install requests 示例代码 import requests url "http://store.weigou365.cn"res requests.get(url)res.text 执行效果如下&#x…

大数据 - Spark系列《三》- 加载各种数据源创建RDD

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 目录 3.1&#x1f9c0;加载文件(本地) 1. 加载本地文件路径 &#x1f32e;使用te…

Java实现婚恋交友网站 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 会员管理模块2.3 新闻管理模块2.4 相亲大会管理模块2.5 留言管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 会员信息表3.2.2 新闻表3.2.3 相亲大会表3.2.4 留言表 四、系统展示五、核心代码5.…

Redis核心技术与实战【学习笔记】 - 20.Redis原子操作及并发访问

概述 使用 Redis 时&#xff0c;不可避免地会遇到并发访问的问题&#xff0c;比如说如果多个用户同时下单&#xff0c;就会对缓存在 Redis 中的商品库存并发更新。一旦有了并发写操作&#xff0c;数据就会被修改&#xff0c;如果我们没有对并发写请求做好控制&#xff0c;就可…

MySQL-----DML基础操作

DML语句 DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进行增删改操作。 ▶ 添加数据(INSERT) 【语法】 1. 给指定字段添加数据 INSERTO 表名 (字段名1&#xff0c;字段名2,...) VALUES (值1&#xff0c;值2,...); 2.给全…

蓝桥杯---生日蜡烛

某君从某年开始每年都举办一次生日party&#xff0c;并且每次都要吹熄与年龄相同根数的蜡烛&#xff0c;现在算起来&#xff0c;他一共吹熄了236根蜡烛。请问,他从多少岁开始过生日party的? 请填写他开始过生日 party的年龄数。 注意:你提交的应该是一个整数&#xff0c;不要…

区间时间检索

前端 <el-col :md"6" v-if"advanced"><el-form-item :label"$t(inRecord.column.createTime)"><el-date-pickerstyle"width: 100%;"v-model"daterangeCreateTime"value-format"yyyy-MM-dd"type&qu…

JavaScript鼠标拖放(Drag and Drop)

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 拖放是现代界面不可或缺的交互方式之一。本文将介绍如何用JavaScript…

界面组件DevExpress中文教程 - 如何使用UI本地化客户端工具本地化应用

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。 获取DevExpress v23.2正式版下载(Q技术交流&#xff1a;909157416&#xff09; 在2023年12月…

django+flask网上购物商城系统的设计与实现python-vue

全球经济在快速的发展&#xff0c;中国更是进步飞速&#xff0c;这使得国内的互联网技术进入了发展的高峰时期&#xff0c;这让中外资本不断转向互联网这个大市场[3]。在这个信息高度发达的现在&#xff0c;利用网络进行信息管理改革已经成为了人们追捧的一种趋势。“网上购物系…

华西建筑智能化团队助力建筑行业转型升级

华西建筑智能化团队全力推进建筑数字化转行。华西建筑智能化团队作为专业的机电安装及弱电智能化项目施工管理团队&#xff0c;先后实施了多个大型机电、智能化工程项目&#xff0c;包括&#xff1a;智慧医院项目、智能楼宇项目、机场/体育场馆/展馆等大型公共建筑及科研单位园…

sqli-labs-master靶场训练笔记(21-38|精英级)

2024.1.30 level-21 (cookie 注入数据加密) 从页面上就可以看出这次的数据被 baes64 加密了 中国有句古话&#xff1a;师夷长技以制夷 &#xff0c;用base64加密后的数据即可爆出数据 加密前&#xff1a; admin and updatexml(1,concat(~,(select database()),~),1) and …

搜索专项---Flood Fill

文章目录 池塘计数城堡问题山峰与山谷 一、池塘计数OJ链接 1.BFS做法 #include <bits/stdc.h>#define x first #define y secondtypedef std::pair<int,int> PII;constexpr int N1010;int n,m; char g[N][N]; bool st[N][N];//用来表示已经记录过的 std::queue&…

javaEE - 21( 15000字 Tomcat 和 HTTP 协议入门 -2)

一&#xff1a; HTTP 响应 1.1 认识 “状态码” (status code) 状态码表示访问一个页面的结果. (是访问成功, 还是失败, 还是其他的一些情况…)&#xff0c;以下为常见的状态码. 1.1.1 200 OK 这是一个最常见的状态码, 表示访问成功. 抓包抓到的大部分结果都是 200 HTTP/…

Unity引擎学习笔记之【混合动画操作】

混合动画Hybrid Animation Unity中的Blend Tree是一种动画混合技术&#xff0c;它允许开发者通过添加多个动画片段&#xff08;例如奔跑、行走、跳跃等&#xff09;来创建复杂的角色动画。Blend Tree允许在不同的状态下平滑地过渡并混合不同的动画。例如&#xff0c;在奔跑和行…