什么是布隆过滤器?告诉你某事一定不存在或可能存在。当布隆过滤器说某物存在时,它可能不存在;当布隆过滤器说某物不存在时,它一定不存在。与Set、Map等数据结构相比,布隆过滤器可以更高效地插入和查询,占用空间更小。它也有一个缺点,就是在判断某物是否存在时可能会误判。但只要参数设置合理,其精度可以控制得比较准确,只有很小的误判概率。Redis中Bloomfilter之前的Bloomfilter可以使用Redis中的位图操作来实现。直到Redis4.0版本提供了插件功能,Redis官方提供的Bloomfilter才正式登场。Bloomfilter作为插件加载到RedisServer中,将为Redis提供强大的Bloom去重功能。Bloomfilter的基本使用在Redis中,Bloomfilter有两个基本命令,分别是:bf.add:向Bloomfilter添加元素,类似于set的sadd命令,但是bf.add命令只能添加一个一次元素。如果要一次添加多个元素,可以使用bf.madd命令。bf.exists:判断一个元素是否在过滤器中,类似于set的sismember命令,但是bf.exists命令一次只能查询一个元素。如果要一次查询多个元素,可以使用bf.mexists命令。例如:>bf.addone-more-filterfans1(integer)1>bf.addone-more-filterfans2(integer)1>bf.addone-more-filterfans3(integer)1>bf.existsone-more-filterfans1(integer)1>bf.existsone-more-filterfans2(integer)1>bf.existsone-more-filterfans3(integer)1>bf.existsone-more-filterfans4(integer)0>bf.madd一个多过滤器fans4fans5fans61)(整数)12)(整数)13)(整数)1>bf.mexists一个多过滤器fans4fans5fans6fans71)(整数)12)(整数)13)(integer)14)(integer)0上面的例子,因为元素个数比较少,没有发现误判。当元素较多时,可能会出现误判。如何减少误判?BloomFilter的高级使用上面例子中使用的BloomFilter只是一个带有默认参数的BloomFilter,它是我们第一次使用bf.add命令时自动创建的。Redis还提供了带有自定义参数的布隆过滤器。为了尽量减少布隆过滤器的误判,需要设置合理的参数。在使用bf.add命令添加元素之前,使用bf.reserve命令创建自定义布隆过滤器。bf.reserve命令有3个参数,分别是:key:keyerror_rate:预期错误率,预期错误率越低,需要的空间越大。capacity:初始容量,当实际元素个数超过这个初始容量时,误判率增加。例如:>bf.reserveone-more-filter0.00011000000OK如果对应的key已经存在,执行bf.reserve命令会报错。如果不使用bf.reserve命令创建,而是使用Redis自动创建的Bloomfilter,默认error_rate为0.01,capacity为100。Bloomfilter的error_rate越小,需要的存储空间越大.对于不需要太精确的场景,error_rate可以设置的稍微大一点。布隆过滤器的容量设置太大会浪费存储空间,设置太小又会影响准确率。因此,在使用之前,必须尽可能准确地估计出元素的数量,并且需要加入一定的冗余度。空间以避免实际元素可能意外地比设置值高很多。总之,error_rate和capacity都需要设置一个合适的值。Bloomfilter原理介绍了解了Bloomfilter的使用之后,我们再介绍一下Bloomfilter的原理,做到“知其然,知其所以然”。Redis中布隆过滤器的数据结构是一个大的位数组和几个不同的无偏散列函数(可以平均计算元素的散列值,可以将元素散列到位数组中相对随机的位置)。如下图所示,A、B、C就是三个这样的哈希函数,分别对“OneMoreStudy”和“万茂学院”这两个元素进行哈希运算,并将位数组对应位置置1:到布时在Long过滤器中加入一个元素,使用多个无偏哈希函数对该元素进行哈希计算,计算出一个整数索引值,然后对位数组的长度进行取模运算,得到一个位置。每个无偏哈希函数将获得不同的位置。然后将位数组的这些位置都设置为1,就完成了bf.add命令的操作。查询布隆过滤器是否存在一个元素时,就像添加一个元素一样,它也会计算hash的几个位置,然后检查bit数组中对应的位置是否都是1,只要有一个bit为0即可,那么就说明这个元素不存在于布隆过滤器中。如果这些位置都为1,不完全说明这个元素一定存在于其中。有可能这些位置为1是因为有其他元素的存在,这就是Bloomfilter会误判的原因。布隆过滤器的应用解决了缓存击穿的问题。一般情况下,先检查缓存是否有数据。如果没有缓存,则查询数据库。当数据库中不存在数据时,每次查询都必须访问数据库,这就是缓存击穿。缓存击穿带来的问题是,当有大量请求查询数据库中不存在的数据时,会给数据库造成压力,甚至拖累数据库。可以使用Bloomfilter来解决缓存击穿的问题,将已有数据的key存放在Bloomfilter中。当有新的请求时,先去Bloomfilter检查是否存在,如果数据不存在,直接返回;如果数据存在,则查询缓存并查询数据库。如果黑名单检查发现它存在于黑名单中,就会执行特定的操作。例如:识别垃圾邮件,只要邮箱在黑名单中,就会被识别为垃圾邮件。假设黑名单数以亿计,存储起来会消耗大量的存储空间,布隆过滤器是更好的解决方案。把所有的黑名单都放到Bloomfilter中,当你收到邮件的时候,只要判断邮件地址是否在Bloomfilter中即可。
