解决redis缓存击穿问题之布隆过滤器

布隆过滤器

1. 什么是布隆过滤器

布隆过滤器(Bloom Filter)是一个空间效率很高的数据结构,用于判断一个元素是否在一个集合中。布隆过滤器的核心思想是利用位数组和一系列随机映射函数(哈希函数)来快速判断某个元素是否存在于集合中,但存在一定的误判率。

2. 参数

布隆过滤器的参数主要包括以下几个方面:

(1)预插入元素大小 (n) :预计加入到布隆过滤器中的元素总数

(2)误判率 (p):将不存在的元素误判为存在的概率。在数据量大小一致的情况下,位数组长度越长误判率越小

(3)哈希函数个数 (k) :布隆过滤器使用的哈希函数数量,将输入数据映射到位数组的一个或多个位置上

(4)位数组大小 (m) :表示状态的二进制位的数量

  • k和m都可根据n和p计算得出,所以初始化布隆过滤器时只需要给出n和p的大小即可

  • 布隆过滤器在线计算网址:https://krisives.github.io/bloom-calculator/

3. 布隆过滤器的原理

(1)建立一个二进制向量,并将所有位设置为0

(2)选定K个散列函数,用于对元素进行K次散列,计算向量的位下标

(3)添加元素:当需要添加一个元素到布隆过滤器中时,首先使用多个哈希函数对该元素进行哈希运算,得到多个哈希值。然后,将这些哈希值对应的位数组中的位置设置为1。

(4)查询元素(不存在一定不存在,存在不一定存在):同样使用多个哈希函数对该元素进行哈希运算,然后检查所有哈希值对应的位数组中的位置是否都为1。如果所有位置都为1,则认为该元素可能存在于集合中(注意是“可能”,因为存在误判的可能性);如果有任何一个位置为0,则确定该元素一定不存在于集合中。

假设有元素x,y,z三个元素加入数组中,且哈希函数的个数为3。如上图所示,每个元素根据hash函数计算可得3个哈希值。现有一个w元素对应的哈希值分别为4、13和15,查询元素需要判断三个位置的值都为1。图中下标15的位置为0,所以该元素不存在。

如果再添加一个元素m,且m的哈希值其中有一个为15。这时4、13和15三个位置都为1,就会判断w元素存在,这种误判是由哈希冲突导致的。

如何解决布隆过滤器的误判?(不能完全解决,只能降低概率)

  • 增加哈希函数的数量,降低哈希碰撞的概率

  • 增大数组长度,也可以降低哈希碰撞的概率

4. 布隆过滤器的优缺点

  • 优点

  • 占用空间小:相对于直接存储元素,布隆过滤器使用的空间要小得多。

  • 查询速度快:布隆过滤器的查询操作通常只需要进行少量的位运算和哈希计算,因此速度非常快。

  • 缺点

  • 存在一定的误判率:由于哈希冲突和位数组大小的限制,布隆过滤器无法保证查询结果的绝对准确性。

  • 无法删除元素:布隆过滤器不支持删除操作,因为删除操作会影响其他元素的判断结果。布隆过滤器的使用场景布隆过滤器用于判断一个元素是否可能在一个集合中,可以用于很多场景。

5. 布隆过滤器的使用场景

布隆过滤器用于判断一个元素是否可能在一个集合中,可以用于很多场景。

  • 解决Redis缓存穿透问题

  • 垃圾邮件过滤

  • 用户请求限流,快速判断用户或IP地址的请求频率是否超过了限制

  • 解决新闻推荐过的不再推荐(类似抖音刷过的往下滑动不再刷到)SpringBoot中实现布隆过滤器

6. SpringBoot中实现布隆过滤器解决缓存穿透

(1)引入依赖

Redisson 是一个高性能的 Java 客户端库,用于开发基于 Redis 的分布式应用程序。

<dependency>    <groupId>org.redisson</groupId>    <artifactId>redisson-spring-boot-starter</artifactId>    <version>3.13.6</version></dependency>

XML

(2)布隆过滤器配置

  • 在application.properties中配置好redis的信息,将其注入到ReidsConfig类的属性中,根据属性配置redis的连接客服端

@Value("${spring.redis.host}")String host;@Value("${spring.redis.port}")String port;@Value("${spring.redis.password}")String password;
@Beanpublic RedissonClient redisson(){    Config config = new Config();    config.useSingleServer()    .setAddress("redis://"+host+":"+port)    .setPassword(password);    return Redisson.create(config);}

Java

(3)在商品业务中添加布隆过滤器

@Service
@Slf4j
public class ProductService {
    @Autowired
    ProductDao productDao;
    @Resource
    RedisTemplate<String,Product> redisTemplate;
    @Autowired
    RedissonClient redissonClient;
    RBloomFilter<Integer> productFilter;

    /**
     * 初始化商品数据,将商品数据读入到redis的productFilter中
     */
    @PostConstruct  //项目启动时执行,也可以定时执行,比如每天执行一次
    public void init(){
        // 查询商品列表(只需要查询商品id列表,速度更快)
        List<Product> productList = productDao.selectProductAll();
        productFilter = redissonClient.getBloomFilter("productFilter");
        // 初始化布隆过滤器,设置预计元素个数(结合每天的业务量设置)和误判率
        productFilter.tryInit(productList.size() * 2L,0.01);
        // 添加商品到布隆过滤器中
        productList.forEach(product -> productFilter.add(product.getId()));
    }

    /**
     * 根据id查询商品信息
     */
    public Product getProductById(Integer id){
        String productIdKey = "product."+id;

        // 判断商品是否在布隆过滤器中存在
        if(!productFilter.contains(id)){
            throw new RuntimeException("布隆过滤器不存在该商品");
        }

        // 商品可能存在,在redis中查询商品信息
        Product product = redisTemplate.opsForValue().get(productIdKey);
        if(product!=null){
            log.debug("在redis中查询到商品信息");
            return product;
        }

        // redis中没有,在数据库中查询商品信息
        product = productDao.selectProductById(id);
        if(product==null){
            // 在RBloomFilter工具类中没有找到移除元素的方法,所以这里直接抛出了异常
            throw new RuntimeException("数据库中不存在该商品");
        }

        log.debug("在数据库中有,现存入redis中");
        redisTemplate.opsForValue().set(productIdKey,product);

        return product;
    }

    /**
     * 添加商品,并添加到布隆过滤器中
     */
    public Integer addProduct(Product product){
 
        int affect = productDao.insertProduct(product);

        productFilter.add(product.getId());

        return affect;
    }}

Java

7. 思考

思考一: 如果商品id是有序的且从0开始,使用哪种方式记录表中的所有id比较好? 哪个空间更小?

(1)简单的位图,即商品id作为偏移量,将对应的位置设为1

(2)布隆过滤器,设置误判率为0.01

商品ID是从0开始的连续整数,那么使用位图是更好的选择。位图不仅空间效率更高,而且没有误报的问题。(如果不保证误判率,布隆过滤器空间效率更高)

注意: 使用简单位图的方式时,内存占用由最大的id决定,需要保证id不会大幅度跳动

思考二: 后续数据库中的数据量超过了设置的预添加元素数,布隆过滤器的数组会自动扩容吗?

不会。布隆过滤器一旦初始化,其位数组的大小和哈希函数的数量就是固定的。这意味着它不能自动扩容来适应更多的元素。如果尝试插入的元素数量超过了布隆过滤器的设计容量,误判率将会上升。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是CSRF攻击,该如何防护CSRF攻击

CSRF攻击&#xff08;跨站请求伪造&#xff0c;Cross-Site Request Forgery&#xff09;是一种网络攻击手段&#xff0c;攻击者利用已通过身份验证的用户&#xff0c;诱导他们在不知情的情况下执行未授权操作。这种攻击通常发生在用户登录到可信网站并且有活动的会话时&#xf…

我的AI工具箱Tauri版-FunAsr音频转文本

本教程基于自研的AI工具箱Tauri版进行FunAsr音频转文本服务。 FunAsr音频转文本服务 是自研AI工具箱Tauri版中的一个高效模块&#xff0c;专为将音频或视频中的语音内容自动转化为文本或字幕而设计。用户只需简单配置输入、输出路径&#xff0c;即可通过FunAsr工具快速批量处理…

PCL KD树的使用

目录 一、概述 1.1原理 1.1.1 数据拆分过程 1.1.2 树的构建示例 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1KD树构建与查询&#xff1a; 2.1.2 k近邻搜索 2.1.3半径搜索 2.2完整代码 三、实现效果 3.1处理后点云 3.2数据显示 PCL点云算法汇总及实战…

linux系统维护:给linux的根目录分配更多的额外的磁盘空间,实现系统磁盘容量的平滑升级

目录 一、背景说明 二、概念介绍 1、物理卷&#xff08;Physical Volume, PV&#xff09; 2、卷组&#xff08;Volume Group, VG&#xff09; 3、逻辑卷&#xff08;Logical Volume, LV&#xff09;&#xff1a; 三、操作过程 1、vmware中新增磁盘 2、查看磁盘信息 3、格式化…

安卓13长按电源按键直接关机 andriod13不显示关机对话框直接关机

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 有些设备需要在长按电源键的时候,直接关机。不需要弹出对话框进行询问。 2.问题分析 过滤电源按键,需要在系统里面处理的话,那么我们需要熟悉android的事件分发,然后再…

stm32f411ceu6芯片学习

首先找到对应芯片的数据手册&#xff0c;硬件电路设计参考的是Electrical characteristics这一节&#xff0c;芯片的每一个引脚都会有推荐的电路接线。 基本每个芯片&#xff0c;都可以在数据手册中找到厂家提供的参考电路图&#xff0c;这就是绘制芯片的原理图最基本的依据。 …

力扣题解2390

大家好&#xff0c;欢迎来到无限大的频道。 今日继续给大家带来力扣题解。 题目描述​&#xff08;中等&#xff09;&#xff1a; 从字符串中移除星号 给你一个包含若干星号 * 的字符串 s 。 在一步操作中&#xff0c;你可以&#xff1a; 选中 s 中的一个星号。 移除星号…

清理C盘缓存,删除电脑缓存指令是什么

在处理计算机系统的C盘缓存清理任务时&#xff0c;需要谨慎操作以确保系统的稳定性和数据的安全性。通常&#xff0c;Windows操作系统中并没有直接的“一键清理C盘缓存”的单一命令&#xff0c;因为缓存文件分散存储于多个位置&#xff0c;并且有些缓存对于系统性能至关重要&am…

HarmonyOS元服务与卡片

元服务与卡片 文章目录 一、元服务1.介绍2.常见元服务项目步骤 二、卡片1.介绍2.卡片的创建3.卡片的数据的变更4.卡片的进程间通讯4.1使用工具包4.2使用步骤 5.卡片路由postCardAction&#xff1a;快速拉起后台5.1格式5.2快速拉起指定页面--router5.3调用后台功能--call5.3卡片…

基于Java的房地产在线营销管理系统研究与实现

目录 前言 功能设计 系统实现 获取源码 博主主页&#xff1a;百成Java 往期系列&#xff1a;Spring Boot、SSM、JavaWeb、python、小程序 前言 随着信息技术的迅猛发展&#xff0c;互联网已经渗透到我们生活的方方面面&#xff0c;为各行各业带来了前所未有的变革。房地产…

Linux学习笔记8 理解Ubuntu网络管理,做自己网络的主人

本文讲解了Ubuntu下网络由什么管理&#xff0c;介绍了临时ip和路由的设置方法&#xff0c;介绍了静态持久化网络配置的方法以及各网络管理软件之间的关系。 来看看Ubuntu网络管理。 序言 原本学习ubuntu网络管理就是为了检查nginx安装过程中使用wget获取压缩包为什么解析不出…

Python编码系列—Python适配器模式:无缝集成的桥梁

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

Jenkins怎么设置每日自动执行构建任务?

在 Jenkins 中设置每日自动执行构建任务可以按照以下步骤进行&#xff1a; 一、安装必要插件 确保安装了 “Timestamper” 插件&#xff0c;这个插件可以为构建添加时间戳&#xff0c;方便查看构建的执行时间。 二、配置任务 打开需要设置每日自动执行的 Jenkins 任务。在 …

105.游戏安全项目-基址的技术原理-分析技巧

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要盲目相信…

品牌力是什么?如何评估企业品牌影响力?

品牌影响力&#xff0c;其实就是指品牌在消费者心智中所占据的位置&#xff0c;以及它对消费者购买决策和行为的影响力。如果一个企业的品牌影响力越强&#xff0c;它在消费者心中的印象就越深刻&#xff0c;能够更有效地驱动消费者的购买行为&#xff0c;形成品牌忠诚度&#…

【C++ 学习】多态的基础和原理(10)

目录 前言1. 概念2. 多态的定义及实现2.1 多态的构成条件2.2 虚函数2.3 虚函数重写2.4 虚函数重写的例外2.4.1 协变2.4.1 析构函数的重写 2.5 多态调用和普通调用2.6 函数重写/函数隐藏/函数重载 的对比2.6.1 函数重写2.6.2 函数隐藏2.6.3 函数重载 2.7 C11 final 和override 3…

爬虫--翻页tips

免责声明&#xff1a;本文仅做分享&#xff01; 伪线程 from DrissionPage import ChromiumPage import timepage ChromiumPage() page.get("https://you.ctrip.com/sight/taian746.html") # 初始化 第0页 index_page 0# 翻页点击函数 sleep def page_turn():page…

计算机毕业设计 美妆神域网站的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

IP 协议分析《实验报告》

目录 一、 实验目的 二、实验设备和环境 三、实验记录 1、实验环境搭建 2、IP 协议分析 1.设置抓包接口 2.IP 报文分析 3.报文长度计算 4.生存时间 TTL 5.分析总结 3、IP分片 1.IP 分片简介 2.捕获分组 3.结果分析 一、 实验目的 1、掌握 IP 协议数据报格式&…

硬件工程师笔试面试——保险丝

目录 10、保险丝 10.1 基础 保险丝原理图 保险丝实物图 10.1.1 概念 10.1.2 保险丝的工作原理 10.1.3 保险丝的主要类型 10.1.4 保险丝的选择和使用注意事项 10.2 相关问题 10.2.1 保险丝的额定电流和额定电压是如何确定的? 10.2.2 保险丝的熔断速度对电路保护有何…