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

news2024/11/28 10:45:13

前言:

         在如今的开发中,使用缓存中间件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 {

    @Bean
    public 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 {

    @Autowired
    private 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.coloradmin.cn/o/1175012.html

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

相关文章

什么是51单片机,,如何写代码,并且烧录?

文章目录 1.单片机介绍2.Keil 5操作1.打开Keil 5 3 新建工程3.添加文件并写代码4.添加到group5,设置6.check7.编译8.打开头文件9 调整编辑器 4.烧录1.烧录程序2.串口查询 5.Debug1.首先编译2.调试3.查询 6 51单片机汇编指令1.格式2.符号3.寻址4.数据传送与交换指令5.交换指令6 …

随笔04 Daily Practice

Dear Li Hua&#xff0c; It is the first time that I heve prepared to write a letter to you. Have you ever heard of my name? You dont? That is awful! You ungrateful guy, I have substitutively written countless letters for you in almost 20 years. Every tim…

AI视觉领域流媒体知识入门介绍(二):深入理解GOP

GOP&#xff08;group of pictures&#xff09; 在流行的视频编码算法中&#xff0c;都包含GOP这个概念&#xff0c;例如MPEG-2, H.264, and H.265。 背景 关于视频存储和传输的“size”&#xff1a; Resolution 分辨率 Uncompressed Bitrate 未压缩时的比特率 1280720 (720p…

chrome 一些详细信息查找的地方

可以获得chrome 信息的列表 缓存 #缓存位置# 浏览器事件

打印机:Open the front cover and pull out the drum unit

参考&#xff1a; https://support.brother.com/g/b/faqend.aspx?cgb&langen&prodmfcl8690cdw_eu_as&faqidfaq00000154_082#:~:textReplacing%20the%20drum%20unit%20Make%20sure%20the%20machine,unit%20out%20of%20the%20machine%20until%20it%20stops. 故障现…

【阿里云】通义千问X函数计算FC-爬取免费接口3个月附代码(参加活动可获得京东卡奖励)

目录 前言第一步&#xff1a;打开群内小程序链接报名报名方式一&#xff1a;报名方式二&#xff1a; 第二步&#xff1a;打开专属活动链接第三步&#xff1a;上传作品最后一步&#xff1a;去小程序提交完成记录爬取通义千问接口最后 前言 &#x1f9e1;本次活动可以获得京东卡9…

运动重定向:TeachNet

Vision-based Teleoperation of Shadow Dexterous Hand using End-to-End Deep Neural Network解析 摘要1. 简介2. Related Work2.1 基于视觉的无标记远程操作2.2 基于深度的3D手部姿势估计2.3 远程操作中的主从配对2.4 遥操作映射方法 3. 师生网络Joint angle lossConsistency…

STM32 GPIO 描述

一、GPIO功能描述 每个GPIO端口有两个32位配置寄存器(GPIOx_CRL&#xff0c;GPIOx_CRH) &#xff0c;两个32位数据寄存器 (GPIOx_IDR和GPIOx_ODR) &#xff0c;一个32位置位/复位寄存器(GPIOx_BSRR)&#xff0c;一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR…

【计算机组成与设计】Chisel取指和指令译码设计

本次试验分为三个部分&#xff1a; 目录 设计译码电路 设计寄存器文件 实现一个32个字的指令存储器 设计译码电路 输入位32bit的一个机器字&#xff0c;按照课本MIPS 指令格式&#xff0c;完成add、sub、lw、sw指令译码&#xff0c;其他指令一律译码成nop指令。输入信号名…

腾讯云16核服务器配置有哪些?CPU型号处理器主频性能

腾讯云16核服务器配置大全&#xff0c;CVM云服务器可选择标准型S6、标准型SA3、计算型C6或标准型S5等&#xff0c;目前标准型S5云服务器有优惠活动&#xff0c;性价比高&#xff0c;计算型C6云服务器16核性能更高&#xff0c;轻量16核32G28M带宽优惠价3468元15个月&#xff0c;…

Redis之 redis.conf配置文件

文章目录 前言一、基本配置1.单位2.包含3.网络配置4.通用5.快照6.安全7.限制8.仅追加模式 二、总体主要介绍总结 前言 行家一出手&#xff0c;就知有没有&#xff0c;让一起学习redis.config配置文件。 一、基本配置 Redis 的配置文件位于 Redis 安装目录下&#xff0c;文件名…

【C++代码】接雨水,最近的更大的元素,柱状图中的最大矩阵,单调栈--代码随想录

题目&#xff1a;每日温度 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。…

凡人修仙之灵药篇

一、总纲 &#xff08;1&#xff09;药物均来自拼夕夕&#xff0c;我已经买过的&#xff0c;确认都是正版的&#xff0c;不过急需疗伤的还是线下就医吧&#xff0c; 快递一般都是三天到的。 &#xff08;2&#xff09;具有多种并发症建议去就医。 &#xff08;3&#xff09;两…

【公益案例展】 网易“双碳”智控系统——开源开放赋能绿色发展

‍ 网易天工公益案例 本项目案例由网易天工投递并参与数据猿与上海大数据联盟联合推出的 #榜样的力量# 《2023中国数据智能产业最具社会责任感企业》榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 2020年9月中国明确提出2030年“碳达峰”与2060年“碳中和”…

【黑马程序员】SSM框架——MyBatisPlus

文章目录 前言一、MyBatisPlus 简介1. 入门案例1.1 创建新模块1.2 选择需要的技术集1.3 添加 mp 起步依赖1.4 设置 Jdbc 参数1.5 实体类与表结构1.6 定义数据接口1.7 测试功能 2. MyBatisPlus 概述3. MyBatisPlus 特性 二、标准数据层开发1. 标准数据层 CRUD 功能1.1 Lombok1.2…

Educational Codeforces Round 157 (Rated for Div. 2) D. XOR Construction (思维题)

题目 给定长为n-1(n<2e5)的整数序列a&#xff0c;第i个数a[i](0<a[i]<2n) 构造一个长为n的整数序列b&#xff0c;满足&#xff1a; 1. 0到n-1在b数组中每个数恰好出现一次 2. 对于&#xff0c; 题目保证一定有解&#xff0c;有多组时可以输出任意一组 思路来源 …

腾讯云CVM服务器操作系统镜像大全

腾讯云CVM服务器的公共镜像是由腾讯云官方提供的镜像&#xff0c;公共镜像包含基础操作系统和腾讯云提供的初始化组件&#xff0c;公共镜像分为Windows和Linux两大类操作系统&#xff0c;如TencentOS Server、Windows Server、OpenCloudOS、CentOS Stream、CentOS、Ubuntu、Deb…

图及谱聚类商圈聚类中的应用

背景 在O2O业务场景中&#xff0c;有商圈的概念&#xff0c;商圈是业务运营的单元&#xff0c;有对应的商户BD负责人以及配送运力负责任。这些商圈通常是一定地理围栏构成的区域&#xff0c;区域内包括商户和用户&#xff0c;商圈和商圈之间就通常以道路、河流等围栏进行分隔。…

Java连接Redis并操作Redis中的常见数据类型

目录 一. Java连接Redis 1. 导入依赖 2. 建立连接 二. Java操作Redis的常见数据类型存储 1. Redis字符串(String) 2. Redis哈希(Hash) 3. Redis列表&#xff08;List&#xff09; 4. Redis集合&#xff08;Set&#xff09; 一. Java连接Redis 1. 导入依赖 pom依赖…

Linux--线程-条件控制实现线程的同步

1.条件变量 条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。条件变量与互斥量一起使用时&#xff0c;允许线程以无竞争的方式等待特定的条件发生。 条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量&#xff0c;其他线程在获…