美文网首页Study微服务
Redis高级功能之 - 布隆过滤器

Redis高级功能之 - 布隆过滤器

作者: kyo1992 | 来源:发表于2021-06-01 13:29 被阅读0次

    从一个场景说起

    在刷抖音有刷到过重复内容吗,这么多的推荐内容要推荐给这么多的用户,它是怎么保证每个用户在看推荐内容时,保证不会出现之前已经看过的推荐视频呢?也就是说,抖音是如何实现 推送去重 的呢。

    传统实现上,可能是服务器记录了每个用户看过的所有历史记录,当推荐系统推荐短视频时会从每个用户的历史记录里进行 筛选,过滤掉那些已经存在的记录。问题是当用户量很大,每个用户看过的短视频又很多的情况下,这种方式,推荐系统的去重工作 在性能上是跟不上的。

    如果历史记录存储在关系数据库里,去重就需要频繁地对数据库进行 exists 查询,当系统并发量很高时,数据库是很难抗住压力的。

    如果使用缓存,但是这么多用户这么多的历史记录,如果全部缓存起来,那得需要浪费多大的空间,并且这个存储空间会随着时间呈线性增长,撑不了多久,不缓存性能又跟不上。

    布隆过滤器(Bloom Filter) 就是这样一种专门用来解决去重问题的高级数据结构,类似于bit数组,有那么一点不精确,也存在一定的误判概率,但它能在解决去重的同时,在 空间上能节省 90% 以上,也是非常值得的。

    简介

    布隆过滤器(Bloom Filter实际上 是一个很长的二进制向量和一系列随机映射函数 ,实际上你也可以把它 简单理解 为一个不怎么精确的 set 结构,当你使用它的 contains 方法判断某个对象是否存在时,它可能会误判。但是布隆过滤器也不是特别不精确,只要参数设置的合理,它的精确度可以控制的相对足够精确,只会有小小的误判概率。

    当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那么一定不存在。

    原理

    当一个元素被加入集合时,通过N个散列函数将这个元素映射成一个位数组中的N个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。

    Bloom Filter跟单哈希函数Bit-Map不同之处在于:Bloom Filter使用了N个哈希函数,每个字符串跟N个bit对应。从而降低了冲突的概率。


    image.png

    简单的说一下就是我们先把我们数据库的数据都加载到我们的过滤器中,比如数据库的id现在有:1、2、3
    那就用id:1 为例子他在上图中经过三次hash之后,把三次原本值0的地方改为1
    下次我进来查询如果id也是1 那我就把1拿去三次hash 发现跟上面的三个位置完全一样,那就能证明过滤器中有1的,反之如果不一样就说明不存在了。

    缺点

    bloom filter之所以能做到在时间和空间上的效率比较高,是因为牺牲了判断的准确率、删除的便利性

    • 存在误判,可能要查到的元素并没有在容器中,但是hash之后得到的n个位置上值都是1。如果bloom filter中存储的是黑名单,那么可以通过建立一个白名单来存储可能会误判的元素。

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

    应用场景

    • 解决缓存穿透:我们经常会把一些热点数据放在 Redis 中当作缓存,例如产品详情。通常一个请求过来之后我们会先查询缓存,而不用直接读取数据库,这是提升性能最简单也是最普遍的做法,但是 如果一直请求一个不存在的缓存,那么此时一定不存在缓存,那就会有大量请求直接打到数据库 上,造成 缓存穿透,布隆过滤器也可以用来解决此类问题。

    • 大数据判断是否存在:这就可以实现出上述的去重功能,如果你的服务器内存足够大的话,那么使用 HashMap 可能是一个不错的解决方案,理论上时间复杂度可以达到 O(1)的级别,但是当数据量起来之后,还是只能考虑布隆过滤器。场景有例如爬虫过滤已抓到的url就不再抓,可用bloom filter过滤;前面说的存储用户看过的视频记录; 垃圾邮件过滤等。

    • 垃圾邮件过滤。如果用哈希表,每存储一亿个 email地址,就需要 1.6GB的内存(用哈希表实现的具体办法是将每一个 email地址对应成一个八字节的信息指纹,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email地址需要占用十六个字节。一亿个地址大约要 1.6GB,即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB的内存。而Bloom Filter只需要哈希表 1/8到 1/4 的大小就能解决同样的问题。

    Redis中使用

    Redis 官方 提供的布隆过滤器到了 Redis 4.0 提供了插件功能之后才正式登场。布隆过滤器作为一个插件加载到 Redis Server 中,给 Redis 提供了强大的布隆去重功能。

    实验

    布隆过滤器有两个基本指令,bf.add 添加元素,bf.exists 查询元素是否存在,它的用法和 set 集合的 sadd 和 sismember 差不多。注意 bf.add 只能一次添加一个元素,如果想要一次添加多个,就需要用到 bf.madd 指令。同样如果需要一次查询多个元素是否存在,就需要用到 bf.mexists 指令。

    127.0.0.1:6379> bf.add bl user1
    (integer) 1
    127.0.0.1:6379> bf.add bl user2
    (integer) 1
    127.0.0.1:6379> bf.add bl user3
    (integer) 1
    127.0.0.1:6379> bf.exists bl user1
    (integer) 1
    127.0.0.1:6379> bf.exists bl user2
    (integer) 1
    127.0.0.1:6379> bf.exists bl user3
    (integer) 1
    127.0.0.1:6379> bf.exists bl user4
    (integer) 0
    127.0.0.1:6379> bf.madd bl user4 user5 user6
    1) (integer) 1
    2) (integer) 1
    3) (integer) 1
    127.0.0.1:6379> bf.mexists bl user4 user5 user6 user7
    1) (integer) 1
    2) (integer) 1
    3) (integer) 1
    4) (integer) 0
    127.0.0.1:6379> object encoding bl
    "raw"
    127.0.0.1:6379> type bl
    MBbloom--
    

    相关文章

      网友评论

        本文标题:Redis高级功能之 - 布隆过滤器

        本文链接:https://www.haomeiwen.com/subject/izpwsltx.html