面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

关注过 @Python大星 的小伙伴应该知道,2020 年 4 月 Python 小星最近裸面了阿里巴巴菜鸟网络科技有限公司。

一面中面试官非常重视解决 Redis 缓存穿透问题的利器--布隆过滤器,关于 Python 小星菜鸟二面的情况,后续整理出来。

今天我们来盘一盘“布隆过滤器” 到底是何方妖孽?

一、布隆过滤器(Bloom Filter)

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

布隆

对不起,搞错啦,不是这个“布隆”。

但是,这个“布隆过滤器”中的“布隆” 确实是个人名,1970 年提出的,用来测试一个元素是否在一个集合里。有可能” 误报 “,但肯定不会” 错报 “:对布隆过滤器的一次查询要么返回 “可能在集合中 “,要么” 肯定不在集合里 “。

举个例子,古代进城搜捕凶手,人物画像的特征太多,可能会让凶手蒙混过关进城,但是有些人可以肯定不是凶手,比如高矮胖瘦都不符合画像的。

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

如果你前面理解了,我们再来说下专业术语:

布隆过滤器实际上是一个很长的二进制向量和一系列随机映射函数,可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

二、为什么我们在 Redis 缓存穿透要用布隆过滤器?

如果不用会出现什么情况?

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

我们通常用 Redis 做缓存层,减少 Mysql 数据库的连接次数。

使用 Redis 避免不了一个“缓存穿透”的问题,

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到 DB 中去查询,失去了缓存的意义。在流量大时,可能 DB 就挂掉了,要是有人利用不存在的 key 频繁攻击我们的应用,这就是漏洞。

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

如果我们这里加上“布隆过滤器”,就可以缓解“缓存穿透”对 Mysql 数据库的请求压力。

三、布隆过滤器的原理

布隆过滤器会通过一定的错误率换取空间。

布隆过滤器通过 bit 数组来标识数据

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

假设 1 个元素只占一个坑,位数组中的每个元素都只占用 1 bit ,并且每个元素只能是 0 或者 1。

那么申请一个 100w 个元素的位数组只占用 1000000Bit / 8 = 125000 Byte = 125000/1024 kb ≈ 122kb 的空间。

如果你对 hashmap 原理熟悉的话,这个布隆过滤器的原理就很容易理解了。

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

缺点1:为什么说布隆过滤器有一定误识别率???

这是因为 hash算法计算出来的值会出现冲突,这就是我们常说的hashmap中的 hash 冲突一样,比如我们数据没有 id = 999 的,但是计算出来的值可能和已标识为 1 的值冲突,被“布隆过滤器” 误识别。

那有小伙伴会问,如何提高布隆过滤器的识别率呢?

从 3 个方面可以提高:

① bit 数组长度

② hash 函数的个数

这就和买彩票一样,数字越多,中奖概率越低。hash 函数的个数不是越多越好,需要参考 bit 数组的长度。

③ 如果布隆过滤器存储的是黑名单,那么可以建立小的白名单,存储那些被误判的信息。

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

布隆过滤器误判:

如果布隆过滤器说数据存在,那有可能不存在,输入误判;

如果布隆过滤说数据不存在,那一定不存在。

缺点2:为什么说布隆过滤器删除困难???

一个放入容器的元素映射到 bit 数组的 k 个位置上是 1,删除的时候不能简单的直接置为 0,可能会影响其他元素的判断。

如何解决布隆过滤器删除困难的问题???

Counting Bloom Filter,它将标准 Bloom Filter 位数组的每一位扩展为一个小的计数器 (Counter),在插入元素时给对应的 k(k 为哈希函数个数) 个 Counter 的值分别加 1,删除元素时给对应的 k 个 Counter 的值分别减 1,Counting Bloom Filter 通过多占用几倍的存储空间的代价,给 Bloom Filter 增加了删除操作。

四、布隆过滤器实现

1、如何确定 bit 数组的长度和 hash 函数的个数

已知条件

  • 存储数量为 n
  • 预期误判率 为 fpp(False positive probability)

计算

  • Bit 数组大小 m
  • 哈希函数个数 k

① Bit 数组选择

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

② hash 函数个数

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

2、布隆过滤器的实现

Guava 中就提供了一种 Bloom Filter 的实现。

① 在 springboot 项目中引入 maven 依赖

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

② 布隆过滤器测试

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

测试结果:

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

从上面的简单测试,我们可以看到误判率 320 / 10000 = 0.032.

面试官:都 2020 年,你在干嘛?还不知道布隆过滤器

从源码中我们也可以看出 fpp = 0.03

注意:

BloomFilter.create(Funnels.integerFunnel(), n, fpp);// 可以设置自定义设置误判率

@Python大星 | 文


分享到:


相關文章: