| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 【架构师面试-缓存与搜索-2】-基于布隆过滤器解决缓存穿透 -> 正文阅读 |
|
[Java知识库]【架构师面试-缓存与搜索-2】-基于布隆过滤器解决缓存穿透 |
1:什么是缓存穿透一个常见的缓存使用方式:读请求来了,先查下缓存,缓存有值命中,就直接返回;缓存没命中,就去查数据库,然后把数据库的值更新到缓存,再返回。 缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。 大量数据判断是否存在 这个中间层,是不是用HashMap就好了呢?听起来不错嘛,HashMap时间复杂度可以达到O(1),但是呢因为HashMap数据是在内存里面的,如果大量的数据远超出了服务器的内存呢,那就无法使用HashMap啦,可以使用布隆过滤器来做这个缓冲的事情。 2:布隆过滤器使用场景布隆过滤器主要是在redis中问的比较多,因此像这种数据结构类的主要是考原理以及使用场景。 1:使用场景 1. 钓鱼网站 2. 垃圾邮件检测 3. 解决缓存穿透:通常使用布隆过滤器去解决redis中的缓存穿透:解决方案是redis中bitmap的实现 先举一个例子,在我们身边充斥着各种各样的XX网站,为了不毒害我们祖国的花朵,于是国家网警就开始对这些网站进行割除过滤,问题来了,这些网站的地址其实是不停的更换的,这些垃圾网站和正常网站加起来全世界据统计也有几十亿个。因此就会带来如下的问题: (1)网站数量太多,存储起来比较麻烦。一个地址最起码有32个字节,一亿个地址就需要1.6G的内存。 (2)一个一个比较,太费时间了。 因此布隆过滤器被设计出来了,他是如何做到高效的呢?本质上其实就是一个HASH映射器。他的底层其实是一个超大的二进制向量和一系列随机映射函数。现在我们按照之前的那个例子,我们存储1亿个垃圾网站地址。 第一步:建立一个32亿二进制(比特),也就是4亿字节的向量。全部置0 第二步:网警用八个不同的随机数产生器(F1,F2, …,F8) 产生八个信息指纹(f1, f2, …, f8)。 第三步:用一个随机数产生器 G 把这八个信息指纹映射到 1 到32亿中的八个自然数 g1, g2, …,g8。 第四步:把这八个位置的二进制全部设置为一。 OK,有一天网警查到了一个可疑的网站,想判断一下是否是XX网站,于是就开始检查了。通过同样的方法将XX网站通过哈希映射到32亿个比特位数组上的8个点。如果8个点的其中有一个点不为1,则可以判断该元素一定不存在集合中。 注意:如果两个XX网站通过上面的步骤映射到了相同的8个点上,或者是有一部分点是重合的,这时候该怎么办?于是就出现了误报,也就是说A网站在12345678个点上全部置1,B网站通过同样的方式在23456789上全部置1,这时候B网站来了是不能确定是否包含的。这个逻辑相信各位都理解。这个是最基础的面试问题。 3:布隆过滤器是个啥?布隆过滤器其实就是加快判定一个元素是否在集合中出现的方法。 考点:布隆过滤器只能判定一个元素不在集合里面,不能判断存在!什么意思呢,就是说一个苹果不在篮子里,这个我可以通过布隆过滤器知道,但是一定在篮子里嘛?这个通过布隆过滤器我是不能判定的。 1、怎么理解布隆过滤器?布隆过滤器是一种占用空间很小的数据结构,它由一个很长的二进制向量和一组Hash映射函数组成,它用于检索一个元素是否在一个集合中,空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关 。 2、布隆过滤器原理假设我们有个集合A,A中有n个元素。利用k个哈希散列函数,将A中的每个元素映射到一个长度为a位的数组B中的不同位置上,这些位置上的二进制数均设置为1。如果待检查的元素,经过这k个哈希散列函数的映射后,发现其k个位置上的二进制数全部为1,这个元素很可能属于集合A,反之,一定不属于集合A。 来看个简单例子吧,假设集合A有3个元素,分别为{d1,d2,d3}。有1个哈希函数,为Hash1。现在将A的每个元素映射到长度为16位数组B。 我们现在把d1映射过来,假设Hash1(d1)= 2,我们就把数组B中,下标为2的格子改成1,如下: 我们现在把d2也映射过来,假设Hash1(d2)= 5,我们把数组B中,下标为5的格子也改成1,如下: 接着我们把d3也映射过来,假设Hash1(d3)也等于 2,它也是把下标为2的格子标1: 因此,我们要确认一个元素dn是否在集合A里,我们只要算出Hash1(dn)得到的索引下标,只要是0,那就表示这个元素不在集合A,如果索引下标是1呢?那该元素可能是A中的某一个元素。因为你看,d1和d3得到的下标值,都可能是1,还可能是其他别的数映射的,布隆过滤器是存在这个缺点的:会存在hash碰撞导致的假阳性,判断存在误差。 3:如何减少这种误差呢?搞多几个哈希函数映射,降低哈希碰撞的概率 同时增加B数组的bit长度,可以增大hash函数生成的数据的范围,也可以降低哈希碰撞的概率 我们又增加一个Hash2哈希映射函数,假设Hash2(d1)=6,Hash2(d3)=8,它俩不就不冲突了嘛,如下: 即使存在误差,我们可以发现,布隆过滤器并没有存放完整的数据,它只是运用一系列哈希映射函数计算出位置,然后填充二进制向量。如果数量很大的话,布隆过滤器通过极少的错误率,换取了存储空间的极大节省,还是挺划算的。 开源实现: Google的Guava类库 Twitter的 Algebird 类库 4、关于误报率通过上面的解释相信都大概了解的差不多了,其实就是hash函数映射,由于有hash冲突产生了误报率, 误报率也就是判断失败的情况。 既然是由于hash冲突,那我把布隆过滤器的二进制向量调到很大,这样不就解决了嘛,但是由于数据量比较大,因此现在就要考虑一下误报率和存储效率之间选择一个折中值了。有一个计算公式如下:公式来源于github 假设位数组的长度为m,哈希函数的个数为k。检测某一元素是否在该集合中的误报率是: 如何使得误报率最小,数学问题,求导就可以了。 4:代码实现布隆过滤器上面只是给出了其原理,下面我们代码实现一下。
还有一个SimpleHash,我们看一下
如果您觉得文章好看,欢迎点赞收藏加关注,一连三击呀,感谢!!??? |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/18 10:55:52- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |