当前位置: 首页 > news >正文

重学SpringBoot3-集成Redis(五)之布隆过滤器

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍

重学SpringBoot3-集成Redis(五)之布隆过滤器

  • 1. 什么是布隆过滤器?
    • 基本概念
    • 适用场景
  • 2. 使用 Redis 实现布隆过滤器
    • 项目依赖
    • Redis 配置
  • 3. 创建布隆过滤器服务
  • 4. 布隆过滤器的初始化
  • 5. 使用布隆过滤器进行缓存穿透防护
  • 6. 测试效果
    • 6.1. 启动项目
    • 6.2. 查询存在的商品
    • 6.3. 查询不存在的商品
  • 7. 总结

在高并发场景下,缓存是提升系统性能的重要手段。然而,常规缓存机制中,若遇到大量无效请求访问(请求的 key 不存在于缓存或数据库),就会导致 缓存穿透。为了应对这种问题,布隆过滤器缓存空值 是应对缓存穿透的两大主流方案,布隆过滤器适用于大规模、复杂场景,缓存空值适用于小规模场景。布隆过滤器(Bloom Filter) 能够通过哈希算法判断一个 key 是否可能存在,减少无效请求对数据库的压力。

本篇博客将介绍如何使用 Spring Boot 3Redis 实现布隆过滤器,并结合示例代码来详细讲解布隆过滤器的原理和在 Redis 中的实现方式。

1. 什么是布隆过滤器?

基本概念

布隆过滤器是一种空间效率高的 概率性数据结构,用于快速判断某个元素是否在集合中。它有以下特点:

  • 内存占用小:相比传统的集合结构,布隆过滤器的内存使用更少。
  • 可能存在误判:布隆过滤器只能确定某个元素“可能存在”或“绝对不存在”。但存在误判的概率可以通过调整参数降低。
  • 不支持删除:布隆过滤器不支持删除已添加的元素,删除某个元素会导致误判率增加。

图片来源:https://systemdesign.one/bloom-filters-explained/

图片来源:https://systemdesign.one/bloom-filters-explained/

适用场景

布隆过滤器在以下场景中非常适用:

  • 防止缓存穿透:将不存在的 key 存储在布隆过滤器中,避免大量无效请求直接查询数据库。
  • 防止重复数据:在大规模数据处理中,使用布隆过滤器避免重复处理相同的数据。

2. 使用 Redis 实现布隆过滤器

Redis 提供了开箱即用的布隆过滤器功能,通过 Redis 的插件 RedisBloom,安装过程参考:Redis安装RedisBloom,我们可以非常方便地使用布隆过滤器存储和管理 key。

项目依赖

首先,在 Spring Boot 项目中引入相关依赖,可参考之前文章。需要 Redis 的支持,以及 Spring Data Redis 来实现与 Redis 的交互。

注意: Redisson 提供了对布隆过滤器的支持,具体实现会利用它的 API。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.20.0</version>
</dependency>

Redis 配置

application.yml 文件中配置 Redis 的连接信息,详细请参考上一章重学SpringBoot3-集成Redis(四)之Redisson,进行 Redisson 配置。

spring:redis:redisson:config: |singleServerConfig:address: redis://1.94.26.81:6379   # Redis 连接地址,前缀为 redis://password: redis123456              # 如果 Redis 需要密码认证,则填写密码timeout: 3000                      # 命令执行超时时间(毫秒)

配置类中初始化 Redisson 客户端:

package com.coderjia.boot310redis.config;import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.spring.starter.RedissonProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author CoderJia* @create 2024/10/5 下午 04:53* @Description**/
@Configuration
public class RedissonConfig {@Autowiredprivate RedissonProperties redissonProperties;@Beanpublic RedissonClient redissonClient() throws Exception{Config config = Config.fromYAML(redissonProperties.getConfig());Redisson.create(config);System.out.println("Redisson 已启动");return Redisson.create(config);}}

3. 创建布隆过滤器服务

接下来,我们需要定义一个服务来管理布隆过滤器。利用 Redisson 提供的 API,可以轻松实现布隆过滤器。

import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class BloomFilterService {private static final String BLOOM_FILTER_NAME = "bloomFilter";@Autowiredprivate RedissonClient redissonClient;// 初始化布隆过滤器public void initBloomFilter(long expectedInsertions, double falseProbability) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(BLOOM_FILTER_NAME);bloomFilter.tryInit(expectedInsertions, falseProbability);}// 添加元素到布隆过滤器中public void addToBloomFilter(String key) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(BLOOM_FILTER_NAME);bloomFilter.add(key);}// 检查元素是否存在于布隆过滤器中public boolean mightContain(String key) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(BLOOM_FILTER_NAME);return bloomFilter.contains(key);}
}

代码解释

  1. 初始化布隆过滤器initBloomFilter 方法可以根据期望插入的数量和误判率初始化布隆过滤器。布隆过滤器的大小和哈希函数数量根据这些参数自动计算。
  2. 添加元素addToBloomFilter 方法向布隆过滤器中添加新的 key。
  3. 判断元素是否存在mightContain 方法用来判断某个 key 是否在布隆过滤器中。

4. 布隆过滤器的初始化

通常我们会在应用启动时初始化布隆过滤器,并将数据库中的所有 key 预先加入过滤器。

package com.coderjia.boot310redis.config;import com.coderjia.boot310redis.bean.Product;
import com.coderjia.boot310redis.dao.ProductMapper;
import com.coderjia.boot310redis.service.BloomFilterService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;import java.util.List;/*** @author CoderJia* @create 2024/10/6 下午 12:38* @Description**/
@Slf4j
@Component
public class BloomFilterInitializer implements CommandLineRunner {@Autowiredprivate BloomFilterService bloomFilterService;@Autowiredprivate ProductMapper productMapper;@Overridepublic void run(String... args) throws Exception {// 查询所有产品数据List<Product> all = productMapper.findAll();// 初始化布隆过滤器bloomFilterService.initBloomFilter(all.size(), 0.01);// 将所有产品的ID加入布隆过滤器all.forEach(product -> {bloomFilterService.addToBloomFilter(product.getId().toString());});log.info("初始化布隆过滤器完成,添加产品数:{}", all.size());}
}

代码解释

  • 在应用启动时,通过 CommandLineRunner 初始化布隆过滤器,并将数据库中的所有商品 ID 加入过滤器中。

5. 使用布隆过滤器进行缓存穿透防护

接下来,我们通过一个简单的示例,结合 Redis 的缓存功能和布隆过滤器,展示如何防止缓存穿透。

package com.coderjia.boot310redis.service;import com.coderjia.boot310redis.bean.Product;
import com.coderjia.boot310redis.dao.ProductMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;/*** @author CoderJia* @create 2024/10/6 下午 12:37* @Description**/
@Slf4j
@Service
public class ProductService {@Autowiredprivate BloomFilterService bloomFilterService;@Autowiredprivate ProductMapper productMapper;@Cacheable(value = "product", key = "#p0")public Product getProductById(Long id) {// 使用布隆过滤器防止缓存穿透if (!bloomFilterService.mightContain(id.toString())) {throw new IllegalArgumentException("Product not found!");}log.info("准备查询产品信息,id:{}", id);return productMapper.findById(id).orElseThrow(() -> new IllegalArgumentException("Product not found!"));}
}

代码解释

  1. 在查询商品前,首先通过布隆过滤器判断 key 是否可能存在。若布隆过滤器判断 key 不存在,则直接抛出异常,避免查询数据库。
  2. 如果布隆过滤器判断 key 可能存在,接着通过缓存获取商品数据。如果缓存未命中,则查询数据库。

productMapper 参考:

package com.coderjia.boot310redis.dao;import com.coderjia.boot310redis.bean.Product;
import org.apache.ibatis.annotations.Mapper;import java.util.List;
import java.util.Optional;/*** @author CoderJia* @create 2024/3/16 下午 05:22* @Description**/
@Mapper
public interface ProductMapper {Optional<Product> findById(Long id);List<Product> findAll();
}

Product 也很简单:

package com.coderjia.boot310redis.bean;import lombok.Data;import java.io.Serial;
import java.io.Serializable;/*** @author CoderJia* @create 2024/10/6 下午 12:46* @Description**/
@Data
public class Product implements Serializable {@Serialprivate static final long serialVersionUID = 1L;private Long id;private String name;
}

6. 测试效果

在你的业务逻辑中调用上面创建的 getProductById 方法。

package com.coderjia.boot310redis.demos.web;import com.coderjia.boot310redis.bean.Product;
import com.coderjia.boot310redis.service.LockService;
import com.coderjia.boot310redis.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @author CoderJia* @create 2024/10/5 下午 05:14* @Description**/
@Slf4j
@RestController
public class LockController {@Autowiredprivate ProductService productService;@GetMapping("/get-product")public Product getProduct(@RequestParam("id") Long id) {log.info("准备产品产品信息,id:{}", id);try {Product product = productService.getProductById(id);return product;}catch (Exception e) {log.error("获取产品信息异常,id:{}", id, e);return null;}}
}

6.1. 启动项目

可以看到布隆过滤器的初始化过程,查询出所有的产品信息并添加到布隆过滤器中。

image-20241006190759822

6.2. 查询存在的商品

调用 curl "http://localhost:8080/get-product?id=1" 接口:

image-20241006192152018

6.3. 查询不存在的商品

调用 curl "http://localhost:8080/get-product?id=101" 接口,产品不存在布隆过滤器器中,直接报错。

image-20241006192227320

7. 总结

通过结合 Spring Boot 3RedisRedisson,我们可以非常方便地实现布隆过滤器,来防止缓存穿透问题。在高并发场景下,布隆过滤器是一种有效的工具,可以降低数据库的压力,提升系统性能。布隆过滤器并不是万能的,在某些场景下会有少量误判,但结合 Redis 的强大功能,它依然是防止缓存穿透的最佳选择之一。

关键点总结

  • 布隆过滤器通过空间换时间,能够快速判断元素是否存在,减少无效请求。
  • Redisson 提供了开箱即用的布隆过滤器 API,大大简化了开发工作。
  • 在结合缓存时,布隆过滤器可以显著减少数据库查询,提升系统性能。

相关文章:

重学SpringBoot3-集成Redis(五)之布隆过滤器

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-集成Redis&#xff08;五&#xff09;之布隆过滤器 1. 什么是布隆过滤器&#xff1f;基本概念适用场景 2. 使用 Redis 实现布隆过滤器项目依赖Redis 配置…...

BGP路由原理详解

&#x1f423;个人主页 可惜已不在 &#x1f424;这篇在这个专栏 华为_可惜已不在的博客-CSDN博客 &#x1f425;有用的话就留下一个三连吧&#x1f63c; 目录 一. BGP简介: 二. BGP报文中的角色 BGP的报文 BGP处理过程 BGP有限状态机 BGP属性 三. BGP作用 四. BGP选路 ​…...

Pytorch实现心跳信号分类识别(支持LSTM,GRU,TCN模型)

Pytorch实现心跳信号分类识别(支持LSTM,GRU,TCN模型&#xff09; 目录 Pytorch实现心跳信号分类识别(支持LSTM,GRU,TCN模型&#xff09; 1. 项目说明 2. 数据说明 &#xff08;1&#xff09;心跳信号分类预测数据集 3. 模型训练 &#xff08;1&#xff09;项目安装 &am…...

AI股市预测的可参考价值有几何?

1. AI技术在股市预测中的应用 首先&#xff0c;AI技术在股市预测中的应用主要包括机器学习、深度学习、自然语言处理&#xff08;NLP&#xff09;和量化金融模型等。机器学习算法能够处理和分析大量的金融数据&#xff0c;从中寻找模式和规律。而深度学习特别是在处理复杂的非线…...

【大数据应用开发】2023年全国职业院校技能大赛赛题第02套

需要技能竞赛软件测试资料的同学们可s聊我&#xff0c;详细了解 目录 任务A&#xff1a;大数据平台搭建&#xff08;容器环境&#xff09;&#xff08;15分&#xff09; 任务B&#xff1a;离线数据处理&#xff08;25分 任务C&#xff1a;数据挖掘&#xff08;10分&#xf…...

2. 将GitHub上的开源项目导入(clone)到(Linux)服务器上——深度学习·科研实践·从0到1

目录 1. 在github上搜项目 (以OpenOcc为例&#xff09; 2. 转移到码云Gitee上 3. 进入Linux服务器终端 (jupyter lab) 4. 常用Linux命令 5. 进入对应文件夹中导入项目(代码) 注意&#xff1a;系统盘和数据盘 1. 在github上搜项目 (以OpenOcc为例&#xff09; 把链接复制下…...

毕业设计项目——基于transformer的中文医疗领域命名实体识别(论文/代码)

完整的论文代码见文章末尾 以下为核心内容 摘要 近年来&#xff0c;随着深度学习技术的发展&#xff0c;基于Transformer和BERT的模型在自然语言处理领域取得了显著进展。在中文医疗领域&#xff0c;命名实体识别(Named Entity Recognition, NER)是一项重要任务&#xff0c;旨…...

电子信息类专业技术学习及比赛路线总结(大一到大三)

本文主要是总结到目前为止电子信息类的专业技能、比赛路线&#xff0c;以后会持续更新&#xff0c;希望能为那些热爱电子技术或渴望学习课本之外知识的小伙伴们提供帮助&#xff0c;参加学科竞赛和找工作必备。&#xff08;毕竟很多课本上的内容都没什么用 &#xff09; 1.单片…...

怎么将bash(sh)的所有输出保存到log/txt中?

tee 命令 这会将所有输出同时显示在屏幕上并追加到日志文件中。 bash your_script.sh 2>&1 | tee -a log_file.txt 其他方法不可用 只使用 >> 不会将除了print之外的所有保存 bash your_script.sh >> log_file.txt >> 和 2>&1一起只会保存在日…...

腾讯云服务器上使用Nginx部署的静态网站打开速度慢的原因分析及优化解决方案

目录 前言1. 网站打开速度慢的原因分析1.1 服务器配置不足1.2 网络延迟1.3 Nginx配置不合理1.4 静态资源未优化 2. 网站速度的测试与分析2.1 使用浏览器开发者工具分析2.2 在线工具测试 3. 网站优化的具体方法3.1 服务器配置优化3.2 CDN加速与DNS优化3.3 优化Nginx配置3.3.1 启…...

如何移除 iPhone 上的网络锁?本文筛选了一些适合您的工具

您是否对 iPhone 运营商的网络感到困惑&#xff1f;不用担心&#xff0c;我们将向您介绍 8 大免费 iPhone 解锁服务。这些工具可以帮助您移除 iPhone 上的网络锁&#xff0c;并使您能够永久在网络上使用您的设备。如果您想免费解锁 iPhone&#xff0c;请阅读本文并找到最适合您…...

深度学习:CycleGAN图像风格迁移转换

目录 基础概念 模型工作流程 循环一致性 几个基本概念 假图像&#xff08;Fake Image&#xff09; 重建图像&#xff08;Reconstructed Image&#xff09; 身份映射图像&#xff08;Identity Mapping Image&#xff09; CyclyGAN损失函数 对抗损失 身份鉴别损失 Cyc…...

pytorch和yolo区别

PyTorch与YOLO的区别&#xff1a;一个简明的科普 在深度学习的领域&#xff0c;有许多工具和框架帮助研究人员和开发者快速实现复杂的模型。其中&#xff0c;PyTorch与YOLO&#xff08;You Only Look Once&#xff09;是两个非常重要的名词。本文旨在探讨这两个技术之间的区别&…...

使用树莓派搭建音乐服务器

目录 引言一、搭建Navidrome二、服务穿透三、音流配置 引言 本人手机存储空间128G&#xff0c;网易云音乐6个G&#xff0c;本就不富裕的空间更是雪上加霜&#xff0c;而且重点是&#xff0c;我根本没有听几首歌&#xff0c;清除缓存后&#xff0c;整个软件都还是占用了5个G左右…...

单链表的分解

编写算法创建以整数为数据元素的单向链表&#xff0c;实现将其分解成两个链表&#xff0c;其中一个全部为奇数&#xff0c;另一个全部为偶数&#xff08;尽量利用已知的存储空间&#xff09;。 输入格式: 1 2 3 4 5 6 7 8 9 0 输出格式: 1 3 5 7 9 2 4 6 8 输入样例: …...

[OS] 4.Linux 内核

1. 下载 Linux 内核源代码 首先&#xff0c;你需要从官方站点或镜像站点下载 Linux 内核源代码。 官方源代码&#xff1a;The Linux Kernel Archives 清华大学镜像站点&#xff1a;Index of /kernel/v5.x/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 下载 .t…...

flutter_鸿蒙next_Dart基础③函数

目录 说在前面 1. 函数的基本定义 例子 代码解释 2. 函数的调用 代码解释 3. 可选参数与命名参数 可选参数 代码解释 调用示例 命名参数 代码解释 调用示例 4. 匿名函数与高阶函数 例子 代码解释 说在最后 说在前面 在 Dart 编程语言中&#xff0c;函数是构建…...

基于猎豹优化算法(The Cheetah Optimizer,CO)的多无人机协同三维路径规划(提供MATLAB代码)

一、猎豹优化算法 猎豹优化算法&#xff08;The Cheetah Optimizer&#xff0c;CO&#xff09;由MohammadAminAkbari等人于2022年提出&#xff0c;该算法性能高效&#xff0c;思路新颖。 参考文献&#xff1a; Akbari, M.A., Zare, M., Azizipanah-abarghooee, R. et al. The…...

Linux:进程的创建、终止和等待

一、进程创建 1.1 fork函数初识 #include pid_t fork(void); 返回值&#xff1a;子进程中返回0&#xff0c;父进程返回子进程id&#xff0c;出错返回-1 调用fork函数后&#xff0c;内核做了下面的工作&#xff1a; 1、创建了一个子进程的PCB结构体、并拷贝一份相同的进程地址…...

数值优化基础——基于优化的规划算法

1 最优化问题的一般形式 最优化问题:满足一系列约束的可行域内,找到使得目标函数最小的解 min ⁡ f ( x ) s.t. x...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

数据库——redis

一、Redis 介绍 1. 概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的内存键值数据库系统&#xff0c;具有以下核心特点&#xff1a; 内存存储架构&#xff1a;数据主要存储在内存中&#xff0c;提供微秒级的读写响应 多数据结构支持&…...