彻底理解布隆过滤器怎么解决缓存穿透问题

一.应用场景

实际业务中使用Redis,都是先通过用户插入数据到Mysql中,然后更新缓存到Redis,下一次用户再查询该数据的时候就可以通过Redis来进行查询。

先看下图,是假设的一个用户查询的场景:

首先用户查询的时候会去缓存里面查询,查看是否有该数据,如果不存在,就会去Mysql中查询,然后将数据返回给用户和缓存到Redis;

然后一些非法请求过来, 查询的一些Key在Redis里面不存在,并且Mysql也不存在,这些数据就不会被缓存到Redis中;

此时,这中频繁的发起伪造的请求,就相当于导致Redis的缓存不存在了,所有请求都会穿透Redis的缓存去直接访问Mysql,就会把Mysql搞宕机。

这就是我们所说的缓存穿透问题,解决这个问题可以通过布隆过滤器。

二.什么是BitMaps

在谈布隆过滤器之前,需要先了解Bitmaps,它是Redis的一种高级数据结构。

定义:Bitmaps(位图)是一种数据结构,用于表示一个由二进制位(bit)组成的集合,每个二进制位的值可以是 0 或 1,通常用于表示某些状态或者集合中元素的存在与否,位图在内存中高效地存储和操作大量的布尔值(即 0 或 1),因此在许多场景中,特别是在高效存储和查找时,具有非常重要的应用。

比如现在要去存一个1 3 5 7,在BitMap里面怎么表示?

从上图来看,每个整数映射到它的值(例如,1 映射到第 1 位,3 映射到第 3 位,等等),1存入的时候,存在bit[1],3存在bit[3],5存在bit[5],7存在bit[7],那么就只需要一个bit类型的8位数组,它就只有一个bit的大小。

在BitMap里面又诞生了一个叫做布隆过滤器,在大致了解了布隆过滤器后底层实现后,再来谈谈布隆过滤器。

三.布隆过滤器

1970 年布隆提出了一种布隆过滤器的算法(概率判断算法),用来判断一个元素是否在一个集合中,这种算法由一个二进制数组和一个 Hash 算法组成

比如上面的查询逻辑,当不正常的用户查查询数据的时候,先判断该数据存不存在,不存在直接返回就行了,这样就不会去查询Mysql了。

接下里看一下布隆过滤器的实现:

数据库中存在的数据有A B C,通过Hash算法存储在二进制数组中,并且把对应位置写成1,然后此时过来一个D F数据,接下来要去判断F在不在集合,就需要通过Hash算法计算F出来的位置,此时位置如果是0,代表F不存在,因为不存在的时候默认值就是0;

但是这样可能会出现一个问题,就是Hash算法不能保证存储的数据一定分散在不同的数组位置,所以是会出现Hash冲突的问题,所以说D数据经过计算它所在的位置依然是1,这就是布隆过滤器的误判问题。

1.为什么误判问题不是很重要?

通过Hash计算在数组上不一定是数据库中存在的数据,但是通过Hash计算不在数组的一定不在集合,这种误判的概率是很小的,所以及时出现误判,也是可以运行的。

2.优化方案:

(1)可以通话增大数组来减少Hash冲突的概率;

(2)采用两个Hash算法,只要一Hash算法匹配不存在就不存在:

在 Guava 中,你可以通过实现 Funnel 接口和自定义 Hasher 来使用多个哈希算法,也就是说,可以在 Hasher 中使用两个不同的哈希函数来计算同一个元素的多个哈希值,测试代码如下:

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnel;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.common.base.Charsets;import java.nio.charset.StandardCharsets;public class CustomBloomFilter {public static void main(String[] args) {// 创建一个自定义的Funnel,使用两个哈希算法Funnel<String> funnel = new Funnel<String>() {@Overridepublic void funnel(String from, Hasher into) {// 使用第一个哈希算法(MurmurHash)into.putString(from, StandardCharsets.UTF_8);int murmurHash = Hashing.murmur3_128().hashString(from, StandardCharsets.UTF_8).asInt();into.putInt(murmurHash);// 使用第二个哈希算法(SHA-256)byte[] sha256Hash = Hashing.sha256().hashString(from, StandardCharsets.UTF_8).asBytes();for (byte b : sha256Hash) {into.putByte(b);}}};// 创建布隆过滤器BloomFilter<String> bloomFilter = BloomFilter.create(funnel, 100000, 0.01);// 测试布隆过滤器String value = "hello";bloomFilter.put(value);System.out.println("Contains 'hello'? " + bloomFilter.mightContain(value));}
}

四.缓存击穿的解决

流程如下:

1.创建一个布隆过滤器,用来存储需要缓存的数据的键;

2.如果用户查询的数据不存在布隆过滤器中,直接返回;

3.如果用户查询的数据存在布隆过滤器,通过Redis去获取数据;

4.如果Redis没有获取到数据,再查询Mysql,并将该数据的加入布隆过滤器中。

通过上诉几步,就可以解决缓存击穿问题。

五.代码实现

下面写一段简单代码,举例一下实现步骤:

1.引入布隆过滤器库

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

2. 布隆过滤器初始化和配置

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;import java.nio.charset.StandardCharsets;public class BloomFilterExample {// 创建一个布隆过滤器private static BloomFilter<String> bloomFilter;public static void initBloomFilter() {// 初始化布隆过滤器,预计存储100000个元素,错误率设为0.01bloomFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 100000, 0.01);// 添加初始的元素到布隆过滤器addToBloomFilter("user123");addToBloomFilter("user456");}// 向布隆过滤器添加元素public static void addToBloomFilter(String data) {bloomFilter.put(data);}// 检查元素是否存在布隆过滤器中public static boolean mightContain(String data) {return bloomFilter.mightContain(data);}
}

3.模拟缓存穿透防护

import java.util.HashMap;
import java.util.Map;public class CacheService {// 模拟数据库(简单的 HashMap)private static final Map<String, String> database = new HashMap<>();static {// 模拟数据库中存在的数据database.put("user123", "User 123 Data");database.put("user456", "User 456 Data");}// 模拟缓存private static final Map<String, String> cache = new HashMap<>();public static String getFromCache(String key) {return cache.get(key);}public static void setCache(String key, String value) {cache.put(key, value);}// 模拟从数据库查询数据public static String getFromDatabase(String key) {return database.get(key);}// 使用布隆过滤器防止缓存穿透public static String getData(String key) {// 先检查布隆过滤器,防止缓存穿透if (!BloomFilterExample.mightContain(key)) {return "Data does not exist";  // 直接返回数据不存在}// 查缓存String cachedData = getFromCache(key);if (cachedData != null) {return cachedData;  // 缓存命中}// 如果缓存没有,查数据库String dbData = getFromDatabase(key);if (dbData != null) {// 如果数据库中有,设置到缓存setCache(key, dbData);// 更新布隆过滤器BloomFilterExample.addToBloomFilter(key);return dbData;} else {       return "Data does not exist";  // 数据不存在}}
}

 4.测试代码

public class Main {public static void main(String[] args) {// 初始化布隆过滤器BloomFilterExample.initBloomFilter();// 模拟请求的数据String[] keys = {"user123", "user456", "user789"};for (String key : keys) {System.out.println("Fetching data for: " + key);String result = CacheService.getData(key);System.out.println(result);}}
}

六.总结

1.通过使用布隆过滤器,可以显著减少不必要的数据库查询,防止缓存穿透,提升系统性能;

2.布隆过滤器虽然有误判的可能(会错误地判断一个元素存在),但不会漏判,这保证了数据一致性和系统的稳定性。

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

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

相关文章

Leetcode数学部分笔记

Leetcode数学部分笔记 1. 回文数2. 加一3. 阶乘后的零4. x 的平方根5. Pow(x, n) 1. 回文数 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数 是指正序&#xff08;从左向右&#xff09;和倒序&…

大数据技术之新能源汽车数仓【附学习资源】

第一章 新能源汽车数仓的背景与意义 1.1 新能源汽车产业的爆发式增长 新能源汽车产业近年来呈现出爆发式增长&#xff0c;主要得益于全球范围内对环境保护和能源转型的高度重视。随着全球多个国家和地区对碳排放进行严格控制&#xff0c;政策层面的支持为新能源汽车的普及提供…

Nature:ChatGPT助力学术写作的方法

随着生成式AI技术的飞速发展&#xff0c;它在科研中的潜力也逐渐被探索和实践。在Nature最近的一篇文章里&#xff0c;Dritjon Gruda 副教授提到&#xff0c;生成式AI不仅在论文写作和编辑中扮演着越来越重要的角色&#xff0c;帮助科研人员提高工作效率&#xff0c;还在同行评…

分布式 分布式事务 总结

前言 相关系列 《分布式 & 目录》《分布式 & 分布式事务 & 总结》《分布式 & 分布式事务 & 问题》 分布式事务 所谓分布式事务是指操作范围笼罩多个不同节点的事务。例如对于订单节点&库存节点而言&#xff0c;一次完整的交易需要同时调动两个节…

UnityShaderLab 实现黑白着色器效果

实现思路&#xff1a;取屏幕像素的RGB值&#xff0c;将三个通道的值相加&#xff0c;除以一个大于值使颜色值在0-1内&#xff0c;再乘上一个强度值调节黑白强度。 在URP中实现需要开启Opaque Texture ShaderGraph实现&#xff1a; ShaderLab实现&#xff1a; Shader "Bl…

机器人的动力学前馈控制

机器人前馈技术可加快伺服驱动器内部的误差收敛速度&#xff0c;进而改善机器人的动态响应特性&#xff0c;解决机器人在运动过程中的抖动问题&#xff0c;提升机器人系统的精度和效率。 对于关节型机器人而言&#xff0c;在理想的刚性连接下&#xff0c;若给定每个关节所需要的…

Java基础——多线程基础

一、线程介绍 程序&#xff1a;是为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。简单地说&#xff0c;就是我们写的代码进程&#xff1a; 进程是指运行中的程序&#xff0c;比如我们使用qq&#xff0c;就启动了一个进程。操作系统会为该进程分配内存空间。当我们…

在本地运行大语言模型

1&#xff0c;打开下面网站下载&#xff0c;软件 lm studio 2&#xff0c; 设置模型下载路径 3&#xff0c;没有魔法条件的人&#xff0c;去镜像网站下载模型的镜像文件 、 4&#xff0c;

JUC:Synchronized和锁升级

1. 面试题 谈谈你对Synchronized的理解Sychronized的锁升级你聊聊Synchronized实现原理&#xff0c;monitor对象什么时候生成的&#xff1f;知道monitor的monitorenter和monitorexit这两个是怎么保证同步的嘛&#xff1f;或者说这两个操作计算机底层是如何执行的偏向锁和轻量级…

网络知识:IP数据报知识详解

目录 一、IP数据报概念 二、IPV4数据报报头组成 三、IPV6数据报报头组成 今天给大家分享IP数据库相关的知识,希望对大家进一步了解IP协议提供一些帮助! 一、IP数据报概念 TCP/IP协议的网际层接收到传输层传递过来的数据单元,封装成向下(OSI模型的数据链路层、TCP/IP协…

消息中间件-Kafka2-3.9.0源码构建

消息中间件-Kafka2-3.9.0源码构建 1、软件环境 JDK Version 1.8Scala Version 2.12.0Kafka-3.9.0 源码包 下载地址&#xff1a;https://downloads.apache.org/kafka/3.9.0/kafka-3.9.0-src.tgzGradle Version > 8.8Apache Zookeeper 3.7.0 2、源码编译 打开源码根目录修改…

详解:HTTP/HTTPS协议

HTTP协议 一.HTTP是什么 HTTP&#xff0c;全称超文本传输协议&#xff0c;是一种用于分布式、协作式、超媒体信息系统的应用层协议。HTTP往往是基于传输层TCP协议实现的&#xff0c;采用的一问一答的模式&#xff0c;即发一个请求&#xff0c;返回一个响应。 Q&#xff1a;什…

vue中pdf.js的使用,包括pdf显示,跳转指定页面,高亮关键词

目录 一、下载pdf.js 二、引入到本地的项目中 三、实现预览pdf 四、跳转到指定页面 五、利用pdf里面的find查找关键词并可以监听updatefindcontrolstate统计个数 六、修改页面大小为实际大小 七、每次加载pdf都是在第一页 八、修改pdf滚动方式为横向 九、清除pdf缓存 十、pdf.j…

题海拾贝:力扣 231. 2 的幂

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《题海拾贝》、《数据结构与算法之美》 欢迎点赞&#xff0c;关注&#xff01; 目录 …

多级IIR滤波效果(BIQUAD),system verilog验证

MATLAB生成IIR系数 采用率1k&#xff0c;截止频率30hz&#xff0c;Matlab生成6阶对应的biquad3级系数 Verilog测试代码 // fs1khz,fc30hz initial beginreal Sig_Orig, Noise_white, Mix_sig;real fs 1000;Int T 1; //周期int N T*fs; //1s的采样点数// 数组声明…

【实战教程】使用YOLO和EasyOCR实现视频车牌检测与识别【附源码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

word poi-tl 图表功能增强,插入图表折线图、柱状图、饼状图

目录 问题解决问题poi-tl介绍 功能实现引入依赖功能介绍 功能实例饼图模版代码效果图 雷达图&#xff08;模版同饼图&#xff09;代码效果图 柱状图&#xff08;模版同饼图&#xff09;代码效果图 附加CustomCharts 工具类CustomChartSingleSeriesRenderData 数据对象CustomCha…

树莓集团是如何链接政、产、企、校四个板块的?

树莓集团作为数字影像行业的积极探索者与推动者&#xff0c;我们通过多维度、深层次的战略举措&#xff0c;将政、产、企、校四个关键板块紧密链接在一起&#xff0c;实现了资源的高效整合与协同发展&#xff0c;共同为数字影像产业的繁荣贡献力量。 与政府的深度合作政府在产业…

SQL 计算字段:算术计算

计算字段的一种常见用途是对检索出的数据进行算术计算。举个例子&#xff0c;假设 Orders 表记录了所有订单信息&#xff0c;而 OrderItems 表则记录了每个订单中的物品详情。以下 SQL 语句查询订单号为 20008 的所有物品&#xff1a; SELECT prod_id, quantity, item_price …

Apache-HertzBeat 开源监控默认口令登录

0x01 产品描述: HertzBeat(赫兹跳动) 是一个开源实时监控系统,无需Agent,性能集群,兼容Prometheus,自定义监控和状态页构建能力。HertzBeat 的强大自定义,多类型支持,高性能,易扩展,希望能帮助用户快速构建自有监控系统。0x02 漏洞描述: HertzBeat(赫兹跳动) 开源实时…