什么是布隆过滤器?如何解决高并发缓存穿透问题?

news2024/11/28 0:38:53

日常开发中,大家经常使用缓存,但是你知道大型的互联网公司面对高并发流量,要注意缓存穿透问题吗!!!    本文会介绍布隆过滤器,空间换时间,以较低的内存空间、高效解决这个问题。

本篇文章的目录:

1、性能不够,缓存来凑

现在的年轻人都喜欢网购,没事就逛逛淘宝,剁剁手,买些自己喜欢的东西,释放下工作压力。

地址:

https://detail.tmall.com/item.htm?id=628993216729

上图是一个天猫 iphone12 的商品详情页,id表示商品的编号

我们都知道淘宝的访问量是非常高的,为了提升系统的吞吐量,做了很多性能优化,其中非常重要一点是将信息异构到缓存中。

有句话说的好:性能不够,缓存来凑。

但是,使用缓存时,我们要关注一个重要问题,如果缓存没有命中怎么办?

 

2、缓存没有命中,怎么办?

  • ①我们先查询缓存,判断缓存中是否有数据

  • ②如果有数据,直接返回

  • ③如果缓存为空,我们需要再查一次数据库,并将数据格式异构化,然后预热到缓冲中,然后将结果返回

注意:

步骤 ③ 存在风险漏洞,如果缓存中数据不存在,压力会转嫁给数据库。假如被竞争对手利用,搞无效请求流量攻击,瞬间大量请求打到数据库中,对系统性能产生很大影响,很容易把数据库打挂,这种现象称为缓存穿透。

3、那么如何处理缓存穿透?

我们的思路是,缓存中能不能判断这个数据库值的存在性,如果真的不存在,直接返回,也避免一次数据库查询。

由于不存在是个无限边界,所以,我们采用反向策略,将存在的值建立一个高效的检索。每次缓存取值时,先走一次判空检索。

简单归纳下,这个框架的要求:

  • 快速检索

  • 内存空间要非常小

经调研,我们发现布隆过滤器具备以上两个条件。

4、什么是布隆过滤器?

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。

  • 优点:空间效率和查询时间都远远超过一般的算法。

  • 缺点:有一定的误识别率,删除困难。

5、布隆过滤器如何构建?

布隆过滤器本质上是一个 n 位的二进制数组,用0和1表示。

假如我们以商品为例,有三件商品,商品编码分别为,id1id2id3

a)首先,对id1,进行三次哈希,并确定其在二进制数组中的位置。

三次哈希,对应的二进制数组下标分别是 2、5、8,将原始数据从 0 变为 1。

b)对id2,进行三次哈希,并确定其在二进制数组中的位置。

三次哈希,对应的二进制数组下标分别是 2、7、98,将原始数据从 0 变为 1。

下标 2,之前已经被操作设置成 1,则本次认为是哈希冲突,不需要改动。

Hash 规则:如果在 Hash 后,原始位它是 0 的话,将其从 0 变为 1;如果本身这一位就是 1 的话,则保持不变。

6、布隆过滤器如何使用?

跟初始化的过程有点类似,当查询一件商品的缓存信息时,我们首先要判断这件商品是否存在。

  • 通过三个哈希函数对商品id计算哈希值

  • 然后,在布隆数组中查找访问对应的位值,0或1

  • 判断,三个值中,只要有一个不是1,那么我们认为数据是不存在的。

注意:布隆过滤器只能精确判断数据不存在情况,对于存在我们只能说是可能,因为存在Hash冲突情况,当然这个概率非常低。

7、如何减少布隆过滤器的误判?

a)增加二进制位数组的长度。这样经过hash后数据会更加的离散化,出现冲突的概率会大大降低

b)增加Hash的次数,变相的增加数据特征,特征越多,冲突的概率越小

8、布隆过滤器会不会很费内存?

带着疑问,我们来做个实验

假设有1千万个数据,我们需要记录其是否存在。存在的话标记1,不存在标记为0。技术选型,框架采用Redis的BitMap存储。

数据初始化预热代码:

redisTemplate.executePipelined(new RedisCallback<Long>() {
    @Nullable
    @Override
    public Long doInRedis(RedisConnection connection) throws DataAccessException {
        connection.openPipeline();
        for (int offset = 10000000; offset >= 0; offset--) {
            boolean value = offset % 2 == 0 ? true : false;
            connection.setBit("bloom-filter-data-1".getBytes(), offset, value);
        }
        connection.closePipeline();
        return null;
    }
});
System.out.println("数据预热完成");

性能有点慢,我们也可以采用分组形式,10000个数一组,多批次提交。

数据上传完了后,大小 1.19M,跟我们设想的一样。

计算公式: 10000000/8/1024/1024=1.19M

9、Java应用中,如何使用布隆过滤器?代码实例

Java语言的生态非常繁荣,提供了很多开箱即用的开源框架供我们使用。布隆过滤器也不例外,Java 中提供了一个 Redisson 的组件,它内置了布隆过滤器。

首先引入依赖包

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

代码示例:

/**
 * @author 微信公众号:微观技术
 */
@Test
public void test5() {
    Config config = new Config();
    config.useSingleServer().setAddress("redis://172.16.67.37:6379");
    RedissonClient cient = Redisson.create(config);
    RBloomFilter<String> bloomFilter = cient.getBloomFilter("test5-bloom-filter");
    // 初始化布隆过滤器,数组长度100W,误判率 1%
    bloomFilter.tryInit(1000000L, 0.01);
    // 添加数据
    bloomFilter.add("Tom哥");
    // 判断是否存在
    System.out.println(bloomFilter.contains("微观技术"));
    System.out.println(bloomFilter.contains("Tom哥"));
}

运行结果:

false   // 肯定不存在
true    // 可能存在,有1%的误判率

注意:误判率设置过小,会产生更多次的 Hash 操作,降低系统的性能。通常我们的建议值是 1%

10、布隆过滤器二进制数组,如何处理删除?

初始化后的布隆过滤器,可以直接拿来使用了。但是如果原始数据删除了怎么办?布隆过滤器二进制数组如何维护?

直接删除不行吗?

还真不行!因为这里面有Hash冲突的可能,会导致误删。

怎么办?

方案1:开发定时任务,每隔几个小时,自动创建一个新的布隆过滤器数组,替换老的,有点CopyOnWriteArrayList的味道

方案2:布隆过滤器增加一个等长的数组,存储计数器,主要解决冲突问题,每次删除时对应的计数器减一,如果结果为0,更新主数组的二进制值为0

11、布隆过滤器的应用场景

  • 本文重点介绍的,解决缓存穿透

  • 网页爬虫对URL的去重,避免爬取相同的URL地址

  • 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱

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

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

相关文章

IMX6ULL裸机篇之SPI实验-ICM20608代码实现

一. SPI 实验 SPI实验&#xff1a;学习如何使用 I.MX6U 的 SPI 接口来驱动 ICM-20608&#xff0c;读取 ICM-20608 的六轴数据。 本文学习 SPI通信实验中&#xff0c;涉及从设备的 SPI代码编写。 之前学习了 SPI 主控芯片代码的编写&#xff0c;如下所示&#xff1a; IMX6ULL…

【ROS】RViz使用详解

1、安装 1.1 ROS1-RVIZ RVIZ的ROS1各个ubuntu版本中的安装命令 ubuntu14.04&#xff1a; sudo apt install ros-indigo-rvizubuntu16.04&#xff1a; sudo apt install ros-kinetic-rvizubuntu18.04&#xff1a; sudo apt install ros-melodic-rvizubuntu20.04&#xff1a…

Java厘米级高精准定位系统源码(支持UWB、蓝牙、WIFI定位)

高精准定位系统支持10厘米工业级高精准定位&#xff0c;同时支持UWB&#xff0c;蓝牙&#xff0c;WIFI定位。 ♦高精准定位系统首页为数据统计页面&#xff0c;统计的信息可以分为数量统计、区域告警人数统计、工牌使用量的统计、区域报警率统计以及告警消息的展示。 系统首页…

Pytest教程__常用执行参数详解(3)

前面讲了测试用例的执行方式&#xff0c;也认识了 -v -s 这些参数&#xff0c;那么还有没有其它参数呢&#xff1f;答案肯定是有的&#xff0c;我们可以通过 pytest -h来查看所有可用参数。 从图中可以看出&#xff0c;pytest的参数有很多&#xff0c;但并不是每一个参数都需要…

fiddler高级工具栏中的statistics数据分析工具

Fiddler statistics 板块会统计一个请求开始发出到最终接收并转发的数据&#xff0c;统计和响应的一些信息&#xff1a; 可以使用statistics分页&#xff0c;完成简单的性能测试&#xff0c;查看其接口的响应时间 如图展示&#xff1a; 如图详细解释下每一项的含义&#xff…

grep(General Regular Expression Parser)命令

基本用法 本篇介绍非常有用的命令是grep&#xff0c;这个不寻常的名字代表的是通用正则表达式解析器&#xff08;General Regular Expression Parser&#xff0c;简写为grep&#xff09;。你使用find命令在系统中搜索文件&#xff0c;而使用grep命令在文件中搜索字符串。事实上…

磁盘坏道:sd 2:0:0:0: [sda] Sense Key : Medium Error [current] [descriptor]

现网问题 从log来看磁盘可能存在问题&#xff0c;进一步实锤。 问题定位 通过badblocks扫描磁盘&#xff0c;发现sda磁盘有磁道损坏&#xff0c;建议更换磁盘。 badblocks命令详解 Linux badblocks命令用于检查磁盘装置中损坏的区块,执行指令时须指定所要检查的磁盘装置&…

postman高级使用

概念&#xff1a;让程序代替人判断测试用例执行的结果是否符合预期的一个过程 特点&#xff1a; postman断言使用js编写&#xff0c;断言写在postman的tests中 tests脚本在发送请求之后执行&#xff0c;会把断言的结果最终在testresult中进行展示 常用的postman提供的断言片…

在Django项目中的各个应用中分别编写路由配置文件urls.py

目录 01-通过命令建立三个应用02-配置路由 /index/、/app1/index/、/app2/index/02-1-配置路由 /index/ 并将各个应用的urls.py文件包含进主路由目录中02-02-配置路由/app1/index/02-03-配置路由/app2/index/ 03-编写各个应用的视图views.py 文件04-注册模板文件所在目录05 创建…

CVPR23 | 可编辑3D场景布局的文本引导多对象合成NeRF

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://arxiv.org/abs/2303.13843 0.背景&#xff1a; 最近&#xff0c;文本到图像生成通过将视觉-语言预训练模型与扩散模型相结合&#xff0c;取得了巨大的成功。这些突破也使得强大…

python: read excel and export excel

""" PythonAppReadExcel.py edit&#xff1a; geovindu,Geovin Du,涂聚文 date 2023-06-13 保险 """ # This is a sample Python script. # python.exe -m pip install --upgrade pip # Press ShiftF10 to execute it or replace it with your c…

orbslam 地图点观测距离范围 mfMinDistance,mfMaxDistance 的理解

目的是在不同帧不同距离的范围内观测到同一个地图点 直观理解&#xff0c;由于相机成像小孔成像近大远小 相机在距离特征点i 1米时图像金字塔第0层的 31x31图像区域&#xff0c; 类似于相机在距离 特征点i 最远约米时的图像金字塔第7层的31x31图像区域。 相机在距离特征点i 1…

桥接模式(十)

不管怎么样&#xff0c;都要继续充满着希望 上一章简单介绍了适配器模式(九), 如果没有看过, 请观看上一章 一. 桥接模式 引用 菜鸟教程里面的 桥接模式介绍: https://www.runoob.com/design-pattern/bridge-pattern.html 桥接&#xff08;Bridge&#xff09;是用于把抽象化…

GitHub 2800颗星,支持GPT/Transformer,字节跳动这个开源项目是怎么来的?

AI 绘画、机器翻译、多轮对话……对于各类 AI 相关的功能来说&#xff0c;总有一个痛点&#xff0c;困扰着所有训模型的算法工程师们&#xff1a; 想要效果更好&#xff0c;那么 AI 模型一般都很大&#xff0c;耗费的算力更多不说&#xff0c;运行起来还更费时间&#xff1b; 如…

关键字static,final的使用

关键字&#xff1a;static 概念 是java中的一个关键字 用于修饰成员&#xff08;成员变量和成员方法&#xff09; 类属性、类方法的设计思想 概念&#xff1a; 当我们编写一个类时&#xff0c;其实就是在描述其对象的属性和行为&#xff0c;而并没有产生实 质上的对象&#x…

使用递归SQL实现树形参数的转换(后传前)

1、什么是递归SQL 递归 SQL&#xff08;Recursive SQL&#xff09;是一种 SQL 查询语言的扩展&#xff0c;它允许在查询中使用递归算法。递归 SQL 通常用于处理树形结构或层次结构数据&#xff0c;例如组织结构、产品分类、地理位置等。 递归 SQL 语句通常包含两个部分&#xf…

大数据入门-大数据技术概述(一)

大数据入门系列文章 大数据入门-大数据是什么 一、概念 大数据技术是指在构架大数据平台的时候需要的技术。包含存储系统&#xff0c;数据库&#xff0c;数据仓库&#xff0c;资源调度&#xff0c;查询引擎&#xff0c;实时框架等。下面以我目前所了解到的一些技术做简要介绍…

React学习笔记十-生命周期(旧)

此文章是本人在学习React的时候&#xff0c;写下的学习笔记&#xff0c;在此纪录和分享。此为第十篇&#xff0c;主要介绍React非常重要的组件的生命周期(旧)。要学习react新的生命周期&#xff0c;那必须先学习旧的生命周期。 目录 1.引出生命周期概念 1.1案例 1.1.1案例卸…

snmp默认团体名/弱口令漏洞及安全加固

一、漏洞描述 SNMP&#xff08;简单网络管理协议&#xff09;被广泛用于计算机操作系统设备、网络设备等领域监测连接到网络上的设备是否有任何引起管理上关注的情况。在运行SNMP服务的设备上&#xff0c;若管理员配置不当运行默认团体名/弱口令访问,将导致敏感信息泄露。敏感…

Sentinel源码分析-ProceesorSlotChain调用链及树状资源节点

Sentinel 实现流控&#xff0c;隔离&#xff0c;降级等功能&#xff0c;本质要做两件事&#xff1a; 数据统计&#xff1a; 统计某个资源的访问数据&#xff08;QPS,RT&#xff08;响应时间&#xff09;&#xff0c;异常比例&#xff09;等信息规则判断&#xff1a; 判断流控规…