什么是布隆过滤器
布隆过滤器(Bloom Filter)是一个二进制向量和一系列随机映射函数实现,用于判断一个元素是否在集合中。
如果想要判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。链表,树等数据结构都是这种思路。随着集合中元素的增加,需要的存储空间也越来越大,检索速度也越来越慢。
简单的说布隆过滤器是一种数据结构,是由一串很长的二进制向量组成,可以将其看成一个二进制数组。既然是二进制,那么里面存放的不是0,就是1,但是初始默认值都是0。
如图所示:
工作原理
布隆过滤器(Bloom Filter)是一个高空间利用率的概率性数据结构,由二进制向量(即位数组)和一系列随机映射函数(即哈希函数)两部分组成。
布隆过滤器使用exists()来判断某个元素是否存在于自身结构中。当布隆过滤器判定某个值存在时,其实这个值只是有可能存在;当它说某个值不存在时,那这个值肯定不存在,这个误判概率大约在 1% 左右。
添加数据
BloomFilter 先分配一块内存空间做 bit 数组,数组的 bit 位初始值全部设为 0。当向布隆过滤器中添加一个元素key时,采用 k 个相互独立的 Hash 函数计算,然后将元素 Hash 映射的 K 个位置全部设置为 1。
判断数据是否存在
当检测 key 是否存在时,仍然用这 k 个 Hash 函数计算出 k 个位置,如果位置全部为 1,则表明 key 存在,否则不存在。哈希函数会出现碰撞,所以布隆过滤器会存在误判。
优缺点
优点
- 空间效率高,所占空间小
- 查询时间短
缺点
- 随着数据的增加,误判率会增加
- 还有无法判断数据一定存在
- 另外还有一个重要缺点,无法删除数据
如果想要降低误率,主要的办法就是降低哈希冲突的概率及引入更多的哈希算法。
使用场景
- 大数据判断是否存在:这就可以实现出上述的去重功能,如果你的服务器内存足够大的话,那么使用 HashMap 可 能是一个不错的解决方案,理论上时间复杂度可以达到 O(1)的级别,但是当数据量起来之后,还是只能考虑布隆过滤器。
- 解决缓存穿透:利用布隆过滤器我们可以预先把数据查询的主键,比如用户 ID 或文章 ID
- 缓存到过滤器中。当根据 ID 进行数据查询的时候,判断该 ID 是否存在,若存在的话,则进行下一步处理。若不存在的话,直接返回,这样就不会触发后续的数据库查询,以此减少不存在的行或列的磁盘查找。需要注意的是缓存穿透不能完全解决,我们只能将其控制在一个可以容忍的范围内。
- 业务场景中判断用户是否阅读过某视频或文章,比如抖音或头条,当然会导致一定的误判,但不会让用户看到重复的内容。还有之前自己遇到的一个比赛类的社交场景中,需要判断用户是否在比赛中,如果在则需要更新比赛内容,也可以使用布隆过滤器,可以减少不在的用户查询db或缓存的次数。
- 缓存宕机、缓存击穿场景,一般判断用户是否在缓存中,如果在则直接返回结果,不在则查询db,如果来一波冷数据,会导致缓存大量击穿,造成雪崩效应,这时候可以用布隆过滤器当缓存的索引,只有在布隆过滤器中,才去查询缓存,如果没查询到,则穿透到db。如果不在布隆器中,则直接返回。
- WEB拦截器,如果相同请求则拦截,防止重复被攻击。用户第一次请求,将请求参数放入布隆过滤器中,当第二次请求时,先判断请求参数是否被布隆过滤器命中。可以提高缓存命中率。