Redis布隆过滤器原理与实践

Redis布隆过滤器原理与实践背景在高并发请求时,业务数据一般会对数据进行缓存,提高系统并发量,因为磁盘IO和网络IO相对于内存IO的成百上千倍的性能劣势。做个简单计算,如果我们需要某个数据,该数据从数据库磁盘读出来需要0.1s,从交换机传过来需要0.05s,那么每个请求完成最少0.15s(当然,事实上磁盘和网络IO也没有这么慢,这里只是举例),该数据库服务器每秒只能响应67个请求;而如果该数据存在于本机内存里,读出来只需要10us,那么每秒钟能够响应100,000个请求。通过将高频使用的数据存在离cpu更近的位置,以减少数据传

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

背景

在高并发请求时,业务数据一般会对数据进行缓存,提高系统并发量,因为磁盘IO和网络IO相对于内存IO的成百上千倍的性能劣势。 做个简单计算,如果我们需要某个数据,该数据从数据库磁盘读出来需要0.1s,从交换机传过来需要0.05s,那么每个请求完成最少0.15s(当然,事实上磁盘和网络IO也没有这么慢,这里只是举例),该数据库服务器每秒只能响应67个请求;而如果该数据存在于本机内存里,读出来只需要10us,那么每秒钟能够响应100,000个请求。 通过将高频使用的数据存在离cpu更近的位置,以减少数据传输时间,从而提高处理效率,这就是缓存的意义。

cache

但是在上文中提到过,缓存会存在击穿,穿透等问题,对于此我们可以引入Bloom Filter (布隆过滤器),防止数据库压力过大导致系统异常。

Bloom Filter

如果想要判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。 链表,树等等数据结构都是这种思路. 但是随着集合中元素的增加,我们需要的存储空间越来越大, 检索速度也越来越慢(O(n),O(logn))。

不过还有一种叫作散列表(又叫哈希表,Hash table)的数据结构,它可以通过一个Hash函数将一个 元素映射成一个位阵列中的一个点,这样一来,我们只要看看这个点是不是1就可以知道集合中有没有它了。 这就是布隆过滤器的基本思想。

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

当布隆过滤器说某个值存在时,这个值 可能不存在;当它说不存在时,那么 一定不存在。打个比方,当它说 不认识你时,那就是真的不认识,但是当它说认识你的时候,可能是因为你长得像它认识的另外一个朋友 (脸长 得有些相似),所以误判认识你。

原理

当一个元素加入布隆过滤器中的时候,会进行如下操作:

  1. 使用布隆过滤器中的哈希函数对元素值进行计算,得到哈希值(有几个哈希函数得到几个哈希值)。
  2. 根据得到的哈希值,在位数组中把对应下标的值置为 1。

当我们需要判断一个元素是否存在于布隆过滤器的时候,会进行如下操作:

  1. 对给定元素再次进行相同的哈希计算;
  2. 得到值之后判断位数组中的每个元素是否都为 1,如果值都为 1,那么说明这个值在布隆过滤器中,

如果存在一个值不为 1,说明该元素不在布隆过滤器中。

bloom_1

如上图,

  1. 有8个hash位,且默认值为0,
  2. 当对tencent进行散列hash之后,2,5,7位被置为1,
  3. 继续对cloud进行散列hash后,3,4,6位被置为1。
  4. 这时候我们再对其它词汇other进行hash,假设散列为1、2、3,1位为0,可以判断该单词不存在集合中。

汇总流程 bloom_2

如何选择哈希函数个数和布隆过滤器长度

如果布隆过滤器的长度太小,所有的 bit 位很快就会被用完,此时任何查询都会返回“可能存在”; 如果布隆过滤器的长度太大,那么误判的概率会很小,但是内存空间浪费严重。 类似的,哈希函数的个数越多,则布隆过滤器的 bit 位被占用的速度越快;哈希函数的个数越少, 则误判的概率又会上升。因此,布隆过滤器的长度和哈希函数的个数需要根据业务场景来权衡。

三个参数

  • 哈希函数的个数k;
  • 布隆过滤器位数组的容量m;
  • 布隆过滤器插入的数据数量n;

关于三个值的设定,有位大佬十年前的文章已经做了总结,需要深厚的数学功底,这里不再详细赘述。 文章链接是http://blog.csdn.net/jiaomeng/article/details/1495500

主要的数学结论有:

  • 为了获得最优的准确率,当k = ln2 * (m/n)时,布隆过滤器获得最优的准确性;

优缺点

优点:优点很明显,二进制组成的数组,占用内存极少,并且插入和查询速度都足够快。

缺点:随着数据的增加,误判率会增加;还有无法判断数据一定存在;另外还有一个重要缺点,无法删除数据

场景

  • 大数据判断是否存在:这就可以实现出上述的去重功能,如果你的服务器内存足够大的话,那么使用 HashMap 可

能是一个不错的解决方案,理论上时间复杂度可以达到 O(1)的级别,但是当数据量起来之后,还是只能考虑布隆过滤器。

  • 解决缓存穿透(背景中提到的问题):利用布隆过滤器我们可以预先把数据查询的主键,比如用户 ID 或文章 ID

缓存到过滤器中。当根据 ID 进行数据查询的时候,我们先判断该 ID 是否存在,若存在的话,则进行下一步处 理。若不存在的话,直接返回,这样就不会触发后续的数据库查询。需要注意的是缓存穿透不能完全解决,我们只 能将其控制在一个可以容忍的范围内。

  • 爬虫/ 邮箱等系统的过滤:平时不知道你有没有注意到有一些正常的邮件也会被放进垃圾邮件目录中,这就是使用布隆过滤器 误判 导致的。
  • Google Chrome 使用布隆过滤器识别恶意 URL。

基本操作

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

127.0.0.1:6379> bf.reserve users 0.01 1000
OK
127.0.0.1:6379> bf.add users u1
(integer) 1
127.0.0.1:6379> bf.add users u2
(integer) 1
127.0.0.1:6379> bf.add users u3
(integer) 1
127.0.0.1:6379> bf.exists users u3
(integer) 1
127.0.0.1:6379> bf.madd users user4 user5 user6
1) (integer) 1
2) (integer) 1
3) (integer) 1
127.0.0.1:6379> bf.mexists users user4 user5 user6 user7
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 0
复制代码

bf.reserve 有三个参数,分别是 key、error_rate (错误率) 和 initial_size:

error_rate 越低,需要的空间越大,对于不需要过于精确的场合,设置稍大一些也没有关系, 比如上面说的推送系统,只会让一小部分的内容被过滤掉,整体的观看体验还是不会受到很大影响的;

initial_size 表示预计放入的元素数量,当实际数量超过这个值时,误判率就会提升,所以需要 提前设置一个较大的数值避免超出导致误判率升高;

如果不适用 bf.reserve,默认的 error_rate0.01,默认的 initial_size100

作者:merlinfeng
 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/185030.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【SPSS统计分析】SPSS聚类分析:一个案例演示聚类分析全过程(附SPSS 19.0中文版下载)「建议收藏」

    【SPSS统计分析】SPSS聚类分析:一个案例演示聚类分析全过程(附SPSS 19.0中文版下载)「建议收藏」摘要:案例数据源:有20种12盎司啤酒成分和价格的数据,变量包括啤酒名称、热量、钠含量、酒精含量、价格。数据来自《SPSSforWindows统计分析》。目录问题一:选择那些变量进行聚类?——采用“R型聚类”问题二:20中啤酒能分为几类?——采用“Q型聚类”问题三:用于聚类的变量对聚类过程、结果又贡献么,有用么?——采用“单因素方差分析”问题四:聚类结果的解释?——采用”均值比较描述统计“问题一:选择那些变量进行聚类?——采用“R型聚类”1、现在我们…

    2022年10月18日
    5
  • GIT在Linux上的安装和使用简介

    GIT在Linux上的安装和使用简介

    2021年9月8日
    71
  • mysql 组合索引 前缀_Mysql中的联合索引、前缀索引、覆盖索引[通俗易懂]

    mysql 组合索引 前缀_Mysql中的联合索引、前缀索引、覆盖索引[通俗易懂]索引索引是一种特殊的文件,它们包含着对数据表里所有记录的引用指针。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。联合索引又名复合索引,由两个或多个列的索引。它规定了mysql从左到右地使用索引字段,对字段的顺序有一定要求。一个查询可以只使用索引中的一部分,更准确地说是最左侧部分(最左优先)。如索引是keyindex(a,b,c).可以支持a|a,b|a,b,c…

    2022年5月23日
    40
  • 云服务器上运行python程序(PyCharm本地编辑同步服务器+Anaconda)挂载跑实验详细教程[通俗易懂]

    云服务器上运行python程序(PyCharm本地编辑同步服务器+Anaconda)挂载跑实验详细教程[通俗易懂]云服务器上运行python程序(PyCharm本地编辑同步服务器+Anaconda)挂载跑实验教程

    2022年6月24日
    72
  • java子窗口获取父窗口句柄_java获得窗口句柄[通俗易懂]

    java子窗口获取父窗口句柄_java获得窗口句柄[通俗易懂]学会用按键精灵获取子窗口句柄来源:按键学院【按键精灵】电脑的桌面是最顶级的…Windows通过句柄(Handle)识别每个窗体、控件、菜单和菜单项,当程序运行时,它所包含的每个部件都有一个惟一确定的句柄同其他的部件相区别句柄在WindowsAPI中具有举足……其实呢,“抓抓”抓句柄的功能,实现起来是很容易的,我们一起来操作看看。实现功能点击图片控件之后鼠标不松开,到了需要…

    2022年7月14日
    18
  • 移动端开发中遇到的坑点及总结(持续更新)

    移动端开发中遇到的坑点及总结(持续更新)前端在移动端开发中遇到的坑点前言一、newDate()在IOS上出现值为NAN的问题二、移动端中input中的文字使用height和line-height等值,文字居中但光标不居中的问题前言本文主要是记录自己在移动端开发中遇到的一些坑点(持续更新)一、newDate()在IOS上出现值为NAN的问题我们常用newDate()去获取时间戳,例如newDate(“2017-08-11…

    2022年6月24日
    23

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号