【从零开始学习Redis | 第五篇】基于布隆过滤器解决Redis的穿透问题

前言:

         在如今的开发中,使用缓存中间件Redis已经成为一项很广泛的技术,Redis的高性能大大优化了我们的服务器性能,缓解了在高并发的情况下服务器的压力。它基于缓存的形式,在内存中保存数据,减少对磁盘的IO操作。然而尽管Redis有着很多的优点,但仍然有三朵乌云漂浮在Redis的上空:穿透击穿雪崩。而我们今天就把焦点聚焦于Redis的穿透问题。

目录

前言:

什么是Redis的穿透问题:

布隆过滤器:

基于Spring Boot实现布隆过滤器:

总结:


什么是Redis的穿透问题:

        Redis的穿透问题是指当应用程序查询一个不存在于缓存中的数据时,请求会直接穿透到后端存储系统(如数据库),导致缓存无法发挥作用,增加了后端负载并降低了系统性能。

穿透问题通常发生在以下情况下:

  1. 缓存击穿:某个热门数据在缓存过期后被大量并发请求访问,此时缓存失效,请求会直接访问后端存储系统,导致后端负载过高。
  2. 恶意攻击:有意发送不存在的数据请求,以触发系统的请求流量,浪费服务器资源。

为了解决Redis的穿透问题,可以采取以下措施:

  1. 布隆过滤器(Bloom Filter):使用布隆过滤器可以在缓存层面进行快速的数据存在性检查。布隆过滤器是一种概率型的数据结构,可以高效地判断一个元素是否可能存在于集合中,通过在缓存层进行预先判断,可以防止不存在的数据请求直接穿透到后端存储系统。

  2. 空值缓存:对于后端存储中不存在的数据,可以将其在缓存中设置为空值缓存,即存储一个特殊的空值标识。这样,在下一次查询该数据时,即使缓存中为空值标识,也可以避免请求直接穿透到后端存储系统。

  3. 互斥锁(Mutex):当缓存失效时,可以使用互斥锁来保护后续的查询操作。在获取到锁之后,再从后端存储系统加载数据到缓存中。其他并发请求会等待锁的释放,避免了多个请求同时穿透到后端存储系统。

  4. 热点数据预加载:对于热门数据,可以在系统启动时或低峰期通过批量查询或模拟请求将其提前加载到缓存中,避免缓存冷启动时的穿透问题。

  5. 异步更新缓存:当缓存失效后,可以异步地从后端存储系统加载数据到缓存中,而不是阻塞请求等待数据加载完成。这样可以减少请求的等待时间,提高系统的响应速度。

需要根据具体的业务场景和系统需求选择合适的解决方案,综合考虑性能、复杂度和数据准确性等因素,以确保Redis的穿透问题得到有效解决。

而我们今天就来详细介绍一下布隆过滤器

布隆过滤器:

我们先来简单说一下布隆表达器的思想:

既然 直接访问Redis 可能会存在Redis的穿透问题,那么我们就设置一个容器,这个容器里面记录了Redis中都有哪些数据,而我们以后所有的对于Redis的数据操作,都需要先在这个存储装置中查找我们想要操作的数据是否存在,如果存在,才可以进入Redis进行相关数据操作。

例如这个容器里面说明了Redis中有张三,李四,王五 这三个数据。那么如果我们要查询赵六这个数据,按照以前的思想,就是直接在Redis中查询赵六这个数据。但Redis中并不存在,这就造成了Redis的穿透问题。而为了解决这个问题,我们就使用这个容器,我们先在这个容器中查询是否有赵六这个数据,如果有再查询Redis,如果没有就直接Return false就可以了。

相信通过这么说,大家肯定已经理解了布隆过滤器的思想:布隆过滤器就是一个记录Redis中存在哪些数据的容器

那么现在问题的核心已经变为:我们如何高效的构建这个容器?

因为容器的目的只是为了证明Redis中存在这个数据,如果我们要通过存储这个元素的全部信息来证明Redis中存在这个数据,那简直是太扯淡了。

相信大家自己可以想出很多简化存储数据形式的方法,而我们直接来为大家介绍一下布隆过滤器是怎么构建自己的存储方式的:

整个布隆过滤器,我们可以认为是一个存储0和1的一维数组

而他是怎么通过这些0和1来说明一个元素是否存在于Redis中呢?

布隆过滤器内部有自己的哈希算法,可以对数据进行哈希映射,将其映射为一个一维数组的下标,那么我们就修改这个下标对应的值为1。当我们判断当前数据在Redis中是否存在的时候,我们就使用相同的哈希算法,再次得到一个下标值,检查这个下标对应的位置是否为1。就可以快速判断当前数据是否在Redis中存在了。

例如我们的Redis中有张三这个数据,我们把他存储到布隆过滤器中:

此时如果我们输入一个数据是李四,而Hash(李四)=4,我们一查询这个一维数组,下标为4的位置数值为0,这就说明了Redis中不存在李四这个数据,那么我们就直接返回,避免了Redis的穿透问题。

看到这里,相信有善于思考的同学已经发现了问题:万一两个数据经过Hash函数得到的下标值是一样的呢?

假设Redis中存在数据A,Hash(A)=3,而我们输入的数据B,经过Hash算法之后,也得到了下标3,那么岂不是造成错误了?

其实这种情况是存在的,也就是说随之数据量的增加,布隆过滤器是一定会出现错误判断的情况的。而为了减少这种错误,我们的思维也很简单:我多使用几个Hash函数不就好了 ,既然一次得到的下标会重复,我就对一个数据进行多次Hash,把得到的下标所对应的空间都标记为1。在判断数据的时候,我们就进行同样的操作,只有对应的下标空间都为1的时候,才证明该数据在Redis中存在。

例如我们在布隆过滤器中记录张三这个数据的时候,就多进行几次Hash,把得到的下标空间都标记为1。在进行判断数据是否存在的时候,就使用相同Hash函数进行相同次数的操作,判断得到的下标的空间是否为1

也就是说:布隆过滤器的误判率可以通过哈希函数的数量来进行调整。

而哈希函数越多,所映射出来的下标值就越多,下标值越多,一维数组的长度就越长,布隆过滤器的空间复杂度就越高。

基于Spring Boot实现布隆过滤器:

我们不手动实现布隆过滤器,而是直接使用Google Guava中提供的BloomFilter。

1.导入依赖:

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>xxx</version>
</dependency>

2.创建并配置布隆过滤器:

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class BloomFilterConfig {@Beanpublic BloomFilter<String> bloomFilter() {int expectedInsertions = 1000; // 期望的插入数量double fpp = 0.01; // 期望的误判率BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.unencodedCharsFunnel(), expectedInsertions, fpp);return bloomFilter;}
}

3.使用布隆过滤器:

import com.google.common.hash.BloomFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class MyService {@Autowiredprivate BloomFilter<String> bloomFilter;public boolean isElementExists(String element) {return bloomFilter.mightContain(element);}public void addElement(String element) {bloomFilter.put(element);}
}

 在这里我们再贴一下我自己的一个练手项目的使用:

跟上述的代码其实都差不多,主要在Service层中多添加一个方法,用于把Redis中的所有KEY 都放到布隆过滤器中:然后要设置在启动之后自动执行这个注入:

之后就可以在使用到Redis的方法中使用这个server层类:

这样,我们就在这个项目中实现了基于布隆过滤器来缓解Redis的穿透问题。

所以其实我们可以看到,布隆过滤器的使用难点主要在于:如何在真实业务海量数据的背景下。实现对布隆过滤器的初始化,因为我们要直接从数据库中拿数据,这种大规模的IO操作势必会给服务器来带很大的压力

而我由于能力限制,想不出太多的方法,也无法真实模拟海量数据背景,所以在这方面有所欠缺。

而我能够想出的方法有:

1.创建定时任务,分批存储数据到布隆过滤器中。

2.创建多个布隆切片,分批处理数据。

不知道在实际业务开发中,我们是怎么使用布隆过滤器的,如果有知道的大佬还请赐教。

总结:

布隆过滤器是一种高效的概率型数据结构,用于快速判断一个元素是否可能存在于一个集合中。通过位数组和多个哈希函数的组合,布隆过滤器可以实现高效的元素插入和查询操作,并且占用较少的内存空间。

总的来说,布隆过滤器具有以下几个关键优点:

  1. 高效的插入和查询性能:布隆过滤器的时间复杂度都是O(k),其中k为哈希函数的数量。这使得它能够在常数时间内快速地判断一个元素是否可能存在于集合中,对于大规模数据集的重复查询非常有效。
  2. 节省内存空间:布隆过滤器只需要存储每个元素的哈希值对应的位数组位置信息,而不需要存储元素本身。相比于其他数据结构,它能够节省大量的内存空间,尤其适用于处理大规模数据集。
  3. 可调控的误判率:通过调整哈希函数的数量和位数组的大小,可以控制布隆过滤器的误判率。根据实际需求和应用场景,可以选择合适的参数配置,以达到平衡误判率和内存消耗的目标。

然而,布隆过滤器也有一些缺点需要注意:

  1. 存在一定的误判率:由于哈希函数的计算结果有可能冲突,布隆过滤器会出现一定程度的误判。这意味着在判断一个元素存在时,可能会出现一定的虚警情况,需要进行进一步的确认。
  2. 无法删除元素:由于布隆过滤器的位数组中的位只能置为1而不能置为0,所以无法从布隆过滤器中删除已插入的元素。如果需要删除元素的功能,布隆过滤器可能不适用。

综上所述,布隆过滤器是一种高效、节省内存的数据结构,通过牺牲一定的精确性来提高查询效率。它在多个领域应用广泛,特别适用于大规模数据集的查询和去重场景。在使用布隆过滤器时,需要根据实际需求选择合适的参数配置,并注意误判率和删除元素的限制。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

69e9169c980f43e0aad31ff9ada88a9c.png

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

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

相关文章

听GPT 讲Rust源代码--library/std(15)

题图来自 An In-Depth Comparison of Rust and C[1] File: rust/library/std/src/os/wasi/io/fd.rs 文件路径&#xff1a;rust/library/std/src/os/wasi/io/fd.rs 该文件的作用是实现与文件描述符&#xff08;File Descriptor&#xff09;相关的操作&#xff0c;具体包括打开文…

✔ ★【备战实习(面经+项目+算法)】 11.5学习

✔ ★【备战实习&#xff08;面经项目算法&#xff09;】 坚持完成每天必做如何找到好工作1. 科学的学习方法&#xff08;专注&#xff01;效率&#xff01;记忆&#xff01;心流&#xff01;&#xff09;2. 每天认真完成必做项&#xff0c;踏实学习技术 认真完成每天必做&…

MFC 基础篇(一)

目录 一.SDK编程 二.为什么要学MFC&#xff1f; 三.MFC能做什么&#xff1f; 四.MFC开发环境搭建 五.MFC项目创建 六.消息映射机制 一.SDK编程 Application Programming Interface 应用程序编程接口。 Software Development Kit 软件开发工具包&#xff0c;一般会包括A…

【入门Flink】- 04Flink部署模式和运行模式【偏概念】

部署模式 在一些应用场景中&#xff0c;对于集群资源分配和占用的方式&#xff0c;可能会有特定的需求。Flink为各种场景提供了不同的部署模式&#xff0c;主要有以下三种&#xff1a;会话模式&#xff08;Session Mode&#xff09;、单作业模式&#xff08;Per-Job Mode&…

小程序如何设置用户同意服务协议并上传头像和昵称

为了保护用户权益和提供更好的用户体验&#xff0c;设置一些必填项和必读协议是非常必要的。首先&#xff0c;用户必须阅读服务协议。服务协议是明确规定用户和商家之间权益和义务的文件。通过要求用户在下单前必须同意协议&#xff0c;可以确保用户在使用服务之前了解并同意相…

分析:如何多线程运行测试用例

这是时常被问到的问题&#xff0c;尤其是UI自动化的运行&#xff0c;过程非常耗时&#xff0c;所以&#xff0c;所以多线程不失为一种首先想到的解决方案。 多线程是针对的测试用例&#xff0c;所以和selenium没有直接关系&#xff0c;我们要关心的是单元测试框架。 unittest …

[GDOUCTF 2023]<ez_ze> SSTI 过滤数字 大括号{等

SSTI模板注入-中括号、args、下划线、单双引号、os、request、花括号、数字被过滤绕过&#xff08;ctfshow web入门370&#xff09;-CSDN博客 ssti板块注入 正好不会 {%%}的内容 学习一下 经过测试 发现过滤了 {{}} 那么我们就开始吧 我们可以通过这个语句来查询是否存在ss…

免费亲人微信聊天记录提取软件新版本v1.1,使用说明,注意事项 2023.11.06

V 1.1 优化了备份速度&#xff0c;新增了备份消息类型的选型&#xff0c;可以选择仅仅备份文本&#xff0c;或者文本与音频&#xff0c;或者文本音频视频图片。 有什么办法可以导出与某个人的微信聊天记录&#xff1f; 只想导出与某个微信好友的聊天记录&#xff0c;有办法做到…

运维知识点-MySQL从小白到入土

MySQL从小白到入土 mysql 服务器安装windows mysql 服务漏洞复现-mysql jdbc反序列化-权限绕过 mysql 服务器安装 https://dev.mysql.com/downloads/mysql/https://www.cnblogs.com/xiaostudy/p/12262804.html 点餐小程序腾讯云服务器安装mysql8 windows mysql 服务 net sta…

1.UML面向对象类图和关系

文章目录 4种静态结构图类图类的表示类与类之间的关系依赖关系(Dependency)关联关系(Association)聚合(Aggregation)组合(Composition)实现(Realization)继承/泛化(Inheritance/Generalization)常用的UML工具reference欢迎访问个人网络日志🌹🌹知行空间🌹🌹 4种静态结构…

cp没有--exclude选项!Linux复制文件夹时如何排除一些文件?

之前使用tar命令压缩文件将时&#xff0c;使用了–exclude选项排除了一些不需要的文件。现在我想复制一个文件夹&#xff0c;但是其中一些文件不需要复制&#xff0c;此时注意到cp命令居然没有–exclude选项。 rsync可以快速地帮助我们完成相同的事情&#xff0c;命令如下&…

【Java 进阶篇】JSP 简单入门

在现代Web开发中&#xff0c;JavaServer Pages&#xff08;JSP&#xff09;是一项非常重要的技术。JSP允许开发者将Java代码嵌入HTML页面&#xff0c;以实现动态内容的生成和呈现。本文将详细介绍JSP的概念、原理以及如何使用JSP来构建Web应用程序。 第一部分&#xff1a;JSP …

如何将 XxlJob 集成达梦数据库

1. 前言 在某些情况下&#xff0c;你的项目可能会面临数据库选择的特殊要求&#xff0c;随着国产化的不断推进&#xff0c;达梦数据库是一个常见的选择。本篇博客将教你如何解决 XxlJob 与达梦数据库之间的 SQL 兼容性问题&#xff0c;以便你的任务调度系统能够在这个数据库中…

章鱼网络进展月报 | 2023.10.1-10.31

章鱼网络大事摘要 1、Louis 成功竞选 NDC 的 HoM 议席&#xff0c;将会尽最大努力推动 NEAR 变革。2、章鱼网络受邀参加在土耳其主办的 Cosmoverse2023&#xff0c;分享 Adaptive IBC 的技术架构。3、2023年10月8日章鱼日&#xff0c;是章鱼网络主网上线2周年的纪念日。 …

机器学习---SVM目标函数求解,SMO算法

1. 线性可分支持向量机 1.1 定义输入数据 假设给定⼀个特征空间上的训练集为&#xff1a; 其中&#xff0c;(x , y )称为样本点。 x 为第i个实例&#xff08;样本&#xff09;。 y 为x 的标记&#xff1a; 当y 1时&#xff0c;x 为正例&#xff1b;当y −1时&#xff0c;x…

vue3项目实践

创建 vue3 项目 node本版&#xff1a;node 16.x.x&#xff0c; 脚手架&#xff1a;create-vue 脚手架工具&#xff0c;底层vite 创建vue3项目&#xff1a;npm init vuelatest setup函数 vue3 单文件组件 1、vite.config.js配置文件基于vite的配置 2、template模板不再要求唯…

docker compose实现容器编排

Compose 使用的三个步骤&#xff1a; 使用 Dockerfile 定义应用程序的环境 使用 compose.yml 定义构成应用程序的服务&#xff0c;这样它们可以在隔离环境中一起运行 最后&#xff0c;执行 docker compose up 命令来启动并运行整个应用程序 为什么需要docker compose Dock…

万宾科技管网水位监测助力智慧城市的排水系统

以往如果要了解城市地下排水管网的水位变化&#xff0c;需要依靠人工巡检或者排查的方式&#xff0c;这不仅加大了人员的工作量&#xff0c;而且也为市政府带来了更多的工作难题。比如人员监管监测不到位或无法远程监控等情况&#xff0c;都会降低市政府对排水管网的管理能力&a…

SpringBoot配置文件优先级

1.idea临时属性 说明&#xff1a;Program arguments配置--server.port8082 --ab&#xff1b;意思是将端口改成了8082。这个优先级最高。 2.resource 说明&#xff1a;创建config文件里面的yml文件。 3.jar包同级&#xff08;yml&#xff09; 说明&#xff1a;创建一个yml文件…

如何去除视频水印?三种简便有效的方法解决视频水印问题

在当今社交媒体时代&#xff0c;视频分享已成为一种流行趋势。然而&#xff0c;很多人在分享自己的作品时却苦于视频上存在的水印&#xff0c;水印通常是出于版权保护或品牌推广的目的而添加到视频中的&#xff0c;但有时它们可能会对用户体验造成负面影响。 如果您正在寻找如何…