文章目录

  • 前言
  • 什么是布隆过滤器
  • 项目中引入布隆过滤器
  • 与缓存结合的最佳实践
  • 场景:高并发用户访问商品详情页(防止缓存穿透)
  • 总结:

前言

okok 我们已经学完了 所有的redis中的常用的数据结构 下面就是进阶
我会用一系列的例子 去讲解 如何使用这些数据结构 以及 如何结合到我们的实际业务代码中去

本文将会介绍布隆过滤器 以及结合缓存的最佳实践

什么是布隆过滤器

Bloom过滤器是一种空间高效的概率性数据结构,用于快速判断一个元素是否可能存在于一个集合中。

基本组成:

位数组(Bit Array): 长度为m的二进制数组,初始全为0
哈希函数集合: k个独立的哈希函数 h₁, h₂, …, hₖ
元素集合: 需要存储的数据集合

工作流程分析:

插入操作 (Add)

  1. 对元素x计算k个哈希值: h₁(x), h₂(x), …, hₖ(x)
  2. 将位数组中对应位置设为1:
    bit[h₁(x) % m] = 1
    bit[h₂(x) % m] = 1
    bit[hₖ(x) % m] = 1 …

查询操作 (Query)

  1. 对元素x计算k个哈希值: h₁(x), h₂(x), …, hₖ(x)
  2. 检查位数组中对应位置: if bit[h₁(x) % m] == 1 AND
    bit[h₂(x) % m] == 1 AND
    … AND
    bit[hₖ(x) % m] == 1:
    return “可能存在” else:
    return “一定不存在”

怎么简单去理解

就是有 n个 Hash表 每次插入数据 首先hash(数据) 到这 N 个 hash表 每个位置设置为1
然后查询的时候
再次使用相同的hash函数去hash(数据) 到这 N 个 hash表 检查每个位置是否为1
若为1 则可能存在通过校验 (疑问 为什么是可能存在呢?)
若存在某一位为0 则一定不存在 (疑问 为什么是一定不存在呢?)

怎么理解:可能存在

因为存在hash冲突啊 还有可能另外的数据也把当前位置 修改成了1 所以是可能而不是一定

怎么理解:一定不存在
你想想 当前受检的hash位置 都是0 说明根本就没有插入过这个数据 如果插入过 则一定会把这一位 置为1 但是为0 说明这个元素没有插入过当前的布隆过滤器

项目中引入布隆过滤器

依赖:

        <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.50.0</version></dependency>

配置类:

@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();// 如果你是单机模式config.useSingleServer().setAddress("redis://127.0.0.1:6379");return Redisson.create(config);}
}
@Service
@RequiredArgsConstructor
public class RedisBloomFilterService {private final RedissonClient redissonClient;public void initBloomFilter(String name, long expectedInsertions, double falseProbability) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(name);// 初始化:预估元素数量 + 期望误判率(如 0.01)bloomFilter.tryInit(expectedInsertions, falseProbability);}public void add(String name, String value) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(name);bloomFilter.add(value);}public boolean mightContain(String name, String value) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter(name);return bloomFilter.contains(value);}
}

测试类

@SpringBootTest
class RedisBloomFilterServiceTest {@Autowiredprivate RedisBloomFilterService bloomFilterService;@Testvoid testBloomFilter() {String filterName = "user:bloom";// 初始化:10 万数据,误判率 1%bloomFilterService.initBloomFilter(filterName, 100_000, 0.01);bloomFilterService.add(filterName, "user_1001");bloomFilterService.add(filterName, "user_1002");assert bloomFilterService.mightContain(filterName, "user_1001"); // trueassert !bloomFilterService.mightContain(filterName, "user_9999"); // very likely false}
}

与缓存结合的最佳实践

三级防护体系
请求 → Bloom过滤器 → 本地缓存 → Redis缓存 → 数据库↓              ↓           ↓            ↓拦截99%无效请求   热点数据    分布式缓存    最终数据源
@Service
public class MultiLevelCacheService {private BloomFilter<String> bloomFilter;      // L0: 布隆过滤器private Cache<String, Object> localCache;     // L1: 本地缓存private RedisTemplate redisTemplate;          // L2: Redis缓存private Database database;                    // L3: 数据库public Object getData(String key) {// L0: Bloom过滤器检查if (!bloomFilter.mightContain(key)) {return null; // 一定不存在}// L1: 本地缓存检查Object data = localCache.getIfPresent(key);if (data != null) {return data;}// L2: Redis缓存检查data = redisTemplate.opsForValue().get(key);if (data != null) {localCache.put(key, data); // 回填本地缓存return data;}// L3: 数据库查询data = database.findById(key);if (data != null) {redisTemplate.opsForValue().set(key, data, Duration.ofMinutes(30));localCache.put(key, data);} else {// 设置空值缓存,防止缓存穿透redisTemplate.opsForValue().set(key, "NULL", Duration.ofMinutes(5));}return data;}
}

场景:高并发用户访问商品详情页(防止缓存穿透)

用户通过 /product/{id} 请求商品详情;

正常流程:Redis 缓存命中 → 返回数据;

若 Redis 未命中,就查 DB → 然后写入 Redis;

问题:恶意请求 / 错误 id 请求不断打穿缓存,导致 DB 被打爆,这就是「缓存穿透」。

如何解决这个问题 需要使用布隆过滤器

  1. 用户请求商品 /product/99999
  2. 系统先检查 BloomFilter.contains(“99999”): → false → 直接拒绝,无需查缓存/数据库 → true → 正常查 Redis 缓存,未命中则查数据库

loomFilter 初始化(商品上线时构建)

@PostConstruct
public void initBloomFilter() {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("bloom:product");bloomFilter.tryInit(1_000_000L, 0.01); // 容量:100w,误判率:1%// 假设所有商品ID:1~1000000for (int i = 1; i <= 1000000; i++) {bloomFilter.add(String.valueOf(i));}
}

Controller 拦截请求:

@GetMapping("/product/{id}")
public ResponseEntity<?> getProduct(@PathVariable String id) {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("bloom:product");if (!bloomFilter.contains(id)) {return ResponseEntity.status(HttpStatus.NOT_FOUND).body("非法商品ID,拒绝访问");}// 查询缓存String redisKey = "product:" + id;Object product = redisTemplate.opsForValue().get(redisKey);if (product != null) return ResponseEntity.ok(product);// 查询数据库(模拟)Product result = productService.queryById(id);if (result != null) {redisTemplate.opsForValue().set(redisKey, result, Duration.ofMinutes(30));return ResponseEntity.ok(result);} else {// 缓存空对象防止缓存穿透redisTemplate.opsForValue().set(redisKey, "NULL", Duration.ofMinutes(10));return ResponseEntity.status(HttpStatus.NOT_FOUND).body("商品不存在");}
}

测试代码

@Test
public void testBloomFilterConcurrency() throws InterruptedException {ExecutorService executor = Executors.newFixedThreadPool(20);for (int i = 0; i < 1000; i++) {final int id = i;executor.submit(() -> {String fakeId = String.valueOf(id);boolean mayExist = redissonClient.getBloomFilter("bloom:product").contains(fakeId);if (mayExist) {System.out.println("合法ID:" + fakeId + " → 继续查缓存/DB");} else {System.out.println("非法ID:" + fakeId + " → 拦截");}});}executor.shutdown();executor.awaitTermination(1, TimeUnit.MINUTES);
}

总结:

布隆过滤器 快速判断一个元素是否可能存在于一个集合中

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

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

相关文章

【AI】人工智能领域关键术语全解析

一、前言 人工智能&#xff08;AI&#xff09;作为当今最热门的技术领域之一&#xff0c;正在深刻改变着我们的生活和工作方式。然而&#xff0c;对于初学者或非技术背景的人士来说&#xff0c;理解AI领域的专业术语可能是一项挑战。本文旨在全面解析人工智能领域的关键术语&a…

【Linux基础知识系列】第四十三篇 - 基础正则表达式与 grep/sed

在Linux系统中&#xff0c;正则表达式是一种强大的文本处理工具&#xff0c;广泛用于文本搜索、替换和批量处理。通过掌握基础正则表达式的语法&#xff0c;结合grep和sed命令&#xff0c;用户可以高效地完成复杂的文本处理任务。无论是数据分析师、软件开发者还是系统管理员&a…

SIMATIC S7-1200的以太网通信能力:协议与资源详细解析

SIMATIC S7-1200的以太网通信能力&#xff1a;协议与资源解析 在工业自动化领域&#xff0c;PLC的通信能力往往直接影响着整个控制系统的灵活性与高效性。西门子SIMATIC S7-1200系列PLC作为一款广泛应用的中小型控制器&#xff0c;其强大的以太网通信功能是其核心优势之一。本文…

什么是高防 IP?从技术原理到实战部署的深度解析

目录 前言 一、高防 IP 的定义与核心价值 二、高防 IP 的技术原理与架构 2.1 流量牵引技术 2.2 流量清洗引擎 2.3 回源机制 三、高防 IP 的核心防护技术详解 3.1 DDoS 攻击防御技术 3.2 高防 IP 的弹性带宽设计 四、实战&#xff1a;基于 Linux 的高防 IP 环境配置 …

NW710NW713美光固态闪存NW719NW720

美光NW系列固态闪存深度解析&#xff1a;技术、性能与市场洞察一、技术架构与核心创新美光NW系列固态闪存&#xff08;包括NW710、NW713、NW719、NW720&#xff09;的技术根基源于其先进的G9 NAND架构。该架构通过5纳米制程工艺和多层3D堆叠技术&#xff0c;在单位面积内实现了…

JVM汇总

1.什么是JVM&#xff1f;Java虚拟机&#xff0c;Java具有自动内存管理等一系列特性&#xff0c;为实现Java跨平台&#xff0c;一次编译处处执行。2.JVM结构图3.类加载器-入口加载class文件&#xff0c;将类信息存放到运行时数据区的方法区内存空间中通过魔数和文件格式来判断是…

2024.09.20 leetcode刷题记录

# 前言 昨天发布了第一遍博客&#xff0c;感觉很好&#xff0c;趁着我现在还是很感兴趣就多发几遍&#xff0c;希望能坚持下去&#xff0c;在这里记录下自己学习成长的经历。 今天是周五&#xff0c;下周一就又要去实习啦&#xff0c;距离上一段实习刚结束一个月&#xff0c;之…

SQLite3 中列(变量)的特殊属性

在 SQLite3 中&#xff0c;列的特殊属性通常通过约束&#xff08;Constraints&#xff09;和数据类型修饰符来定义。这些属性可以在创建表时指定&#xff0c;用于限制数据的完整性或定义特殊行为。以下是 SQLite3 支持的主要特殊属性及其说明&#xff1a; 1. 主键约束&#xff…

Datawhale AI 夏令营:用户洞察挑战赛 Notebook(2)

针对文本聚类优化 优化TF-IDF特征工程# 调整ngram_range&#xff1a;设置为(1, 2)&#xff0c;捕捉单字和双字词&#xff08;如“不错”“不满意”&#xff09;。 # 限制特征数量&#xff1a;通过max_features5000保留高信息密度特征&#xff0c;降低维度。 # 过滤低频/高频词&…

【博主亲测可用】PS2025最新版:Adobe Photoshop 2025 v26.8.1 激活版(附安装教程)

软件简介 Adobe Photoshop 2025是Adobe公司开发的一款图像处理软件。作为行业标准的数字图像编辑工具&#xff0c;其核心定位是创意设计、后期摄影、3D建模和AI驱动创作&#xff0c;适用于专业设计师、摄影师、插画家和多媒体创作者。界面设计简单直观&#xff0c;易于操作&…

unity A星寻路

算法 fCost gCost hCost gCost 是当前节点到移动起始点的消耗&#xff0c;hCost是当前节点到终点的消耗 网格为变成为1的矩形&#xff0c;左右相邻的两个网格直接的gCost为1&#xff0c;斜对角相邻的两个网格的gCost为1.4 hCost 当前网格到终点网格的 水平距离 垂直距离 比如…

十一 Javascript的按值传递

你将知道&#xff1a;“传递” 值是什么意思什么是按值传递传递物品JavaScript 中没有传递引用&#xff01;介绍当需要在 JavaScript 中分配或简单地将一个值传递给其他标识符时&#xff0c;我们就会看到通常所说的 按值传递 。严格来说&#xff0c;JavaScript 中传递值的方式只…

SpringBoot ThreadLocal 全局动态变量设置

需求说明&#xff1a; 现有一个游戏后台管理系统&#xff0c;该系统可管理多个大区的数据&#xff0c;但是需要使用大区id实现数据隔离&#xff0c;并且提供了大区选择功能&#xff0c;先择大区后展示对应的数据。需要实现一下几点&#xff1a; 1.前端请求时&#xff0c;area_i…

如何解决pip安装报错ModuleNotFoundError: No module named ‘logging’问题

【Python系列Bug修复PyCharm控制台pip install报错】如何解决pip安装报错ModuleNotFoundError: No module named ‘logging’问题 摘要&#xff1a; 在使用 PyCharm 2025 控制台通过 pip install 安装第三方库时&#xff0c;常会遇到诸如 ModuleNotFoundError: No module name…

打破技术债困境:从“保持现状”到成为变革的推动者

相信许多在科技行业的同行都面临过类似的挑战&#xff1a;明知系统存在“技术债”&#xff0c;却因为沟通成本、团队压力和短期KPI等原因&#xff0c;难以推动改进&#xff0c;最终陷入“想做却不敢做”的矛盾心态。这不仅影响个人心情&#xff0c;更重要的是&#xff0c;它像一…

Spring Boot 整合 RabbitMQ

Spring Boot 整合 RabbitMQ 一、概述&#xff1a;RabbitMQ 是什么&#xff1f; 你可以把 RabbitMQ 想象成一个「快递中转站」。 比如你在网上买了一本书&#xff0c;卖家&#xff08;生产者&#xff09;把包裹&#xff08;消息&#xff09;交给快递站&#xff08;RabbitMQ&…

Unity Demo-3DFarm详解-其一

我们来拆解一个种田游戏&#xff0c;这个游戏种类内部的功能还是比较模板化的&#xff0c;我们来一点点说。我们大体上分为这么几个部分&#xff1a;农场运营玩法角色与玩家互动物品与背包存档和进度管理用户界面系统农场运营可以大体上分为&#xff1a;种植系统&#xff1a;支…

esp8266驱动下载

问题描述&#xff1a;esp8266插上电脑&#xff0c;设备管理器无法识别&#xff0c;显示为USB serial&#xff08;黄色感叹号&#xff09; 首先确认你的esp8266是不是 CH340 系列的 USB 转串口芯片 CH340驱动下载地址

大语言模型的极限:知识、推理与创造力的边界探析

大语言模型的极限&#xff1a;知识、推理与创造力的边界探析 人工智能领域的快速发展推动了大语言模型&#xff08;LLM&#xff09;的广泛应用&#xff0c;这些模型在文本生成、知识问答和创意表达等方面展现出前所未有的能力。然而&#xff0c;随着应用场景的深化&#xff0c;…

git中的fork指令解释

在Git中&#xff0c;Fork 是指将他人的代码仓库&#xff08;Repository&#xff09;复制到自己的账户下&#xff0c;创建一个完全独立的副本[1][2]。以下是关于Fork的详细说明&#xff1a; Fork的定义与核心作用 定义&#xff1a;Fork是代码托管平台&#xff08;如GitHub&#…