布隆过滤器

Aveiro 2021年11月26日 ⋅ 1286 阅读

1.背景

缓存架构:

①先查询缓存,判断缓存中是否有数据。

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

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

问题:

缓存击穿缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

缓存穿透缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

2.布隆过滤器(Bloom Filter)

一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。

2.1 如何解决缓存穿透

将存在的值建立一个高效的检索。每次缓存取值时,先走一次判空检索。要求:快速检索+内存空间要非常小

2.2 布隆过滤器如何构建

布隆过滤器本质上是一个 n 位的二进制数组,用0和1表示,二进制数组初始化的时候默认都是0。

假如我们以商品为例,有三件商品,商品编码分别为,id1、id2、id3

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

假如对id13次hash,分别对应数组中的下标位置“2,5,8”,那么将二进制数组下标位置“2,5,8”的值变成1

b)同理,对id2,进行三次哈希,并确定其在二进制数组中的位置“2,7,98”。

那么将二进制数组下标位置“2,7,98”的值变成1(如果在 Hash 后,原始位它是 0 的话,将其从 0 变为 1;如果本身这一位就是 1 的话,则保持不变。)

 

2.3 布隆过滤器如何使用

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

通过三个哈希函数对商品id计算哈希值然后,在布隆数组中查找访问对应的位值,0或1判断,三个值中,只要有一个不是1,那么我们认为数据是不存在的。注意:布隆过滤器只能精确判断数据不存在情况,对于存在我们只能说是可能,因为存在Hash冲突情况,当然这个概率非常低。

 

2.4 布隆过滤器如何减少误判

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

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

c)当然增加数组长度和Hash次数的同时要考虑对性能带来的影响

2.5 Java中使用布隆过滤器

使用Redisson 的组件,内置了布隆过滤器(redis bitmap)

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson</artifactId>
  <version>xxx</version>
</dependency>
RBloomFilter bloomFilter = redissonClient.getBloomFilter("test");
// 初始化布隆过滤器,预计统计元素数量为10000,期望误差率为0.03
bloomFilter.tryInit(10000L, 0.03);
bloomFilter.add("desk");
bloomFilter.add("book");
boolean b1 = bloomFilter.contains("a");
boolean b2 = bloomFilter.contains("desk");

2.5 布隆过滤器二进制数组如何进行删除

不能直接删除,因为hash冲突的可能,直接删除可能造成误删
可以创建一个与布隆过滤器二进制数组等长的数组,存储计数器,主要解决冲突问题,每次删除时对应的计数器减一,如果结果为0,更新主数组的二进制值为0

 

2.6 布隆过滤器总结

是一个很长的二进制向量,主要用于判断一个元素是否在一个集合中

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

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

 


全部评论: 0

    我有话说: