

干货,使用布隆过滤器实现高效缓存!
source link: https://www.cnblogs.com/kiba/p/14767430.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

干货,使用布隆过滤器实现高效缓存!
本文主要描述,使用布隆过滤实现高效缓存。文中采用数组做为缓存,如果需要高并发命中,则需将文中的数组换成Redis数据库。
布隆缓存的创建过程如下:
1,先定义缓存bit数组(BitArray),数组的长度就是缓存数据的最大数量。
2,然后将字符串通过哈希运算,求出它的HashCode。
3,然后将HashCode作为伪随机数生成器(Random)的种子,生成一个小于最大数量的正数x。
4,然后将这x作为缓存数组的索引,将数组[x]的值设置为true。
布隆过滤
将获取到的字符串,通过上述前三步运算,计算出数组索引,然后在布隆缓存里取出指定索引的值,如果为True,则缓存存在,可以使用这个字符串去真正的数据缓存中取数据,如果未Fasle,则缓存不存在则去数据库中取数据。
首先建立WinForm项目BloomTest。
然后编写布隆过滤器,代码如下:
public class BloomFilter { //布隆缓存数组 public BitArray BloomCache; //布隆缓存数组的长度 public Int64 BloomCacheLength { get; } public Int64 HashCount { get; } /// <summary> /// /// </summary> /// <param name="bloomCacheLength">布隆缓存数组的长度,默认20000</param> /// <param name="hashCount">hash运算次数,默认3</param> public BloomFilter(int bloomCacheLength = 20000, int hashCount = 3) { BloomCache = new BitArray(bloomCacheLength); BloomCacheLength = bloomCacheLength; HashCount = hashCount; } public void Add(string str) { var hashCode =str.GetHashCode(); Random random = new Random(hashCode); for (int i = 0; i < HashCount; i++) { var x = random.Next((int)(BloomCacheLength - 1)); BloomCache[x] = true; } } public bool IsExist(string str) { var hashCode = str.GetHashCode(); Random random = new Random(hashCode); for (int i = 0; i < HashCount; i++) { if (!BloomCache[random.Next((int)(BloomCacheLength - 1))]) { return false; } } return true; } //错误率查看 public double GetFalsePositiveProbability(double setSize) { // (1 - e^(-k * n / m)) ^ k return Math.Pow((1 - Math.Exp(-HashCount * setSize / BloomCacheLength)), HashCount); } //计算基于布隆过滤器散列的最佳数量,即hashCount的最佳值 public int OptimalNumberOfHashes(int setSize) { return (int)Math.Ceiling((BloomCacheLength / setSize) * Math.Log(2.0)); } }
然后编写布隆过滤器的使用代码,如下:
public partial class Form1 : Form { BloomFilter bloom = new BloomFilter(20000, 3); int setSize = 2000; public Form1() { InitializeComponent(); //生成布隆缓存数组 for (int i = 0; i < setSize; i++) { bloom.Add("kiba" + i); } } private void btnSearch_Click(object sender, EventArgs e) { Stopwatch sw = new Stopwatch(); sw.Start(); string con = tbCon.Text.Trim(); var ret = bloom.IsExist(con); sw.Stop(); lblRet.Text = $@"结果:{ret}{Environment.NewLine} 耗时:{sw.ElapsedTicks}{Environment.NewLine} 错误概率:{bloom.GetFalsePositiveProbability(setSize)}{Environment.NewLine} 最佳数量:{bloom.OptimalNumberOfHashes(setSize)}"; } }
运行项目,点击查询数据。
如上图所示,我们成功命中了,如果在项目中,命中了就可以查询真实缓存了。
布隆缓存存在命中错误,即如果两个数据的哈希运算后值相同,那么久会存在命中失败的问题。
错误概率可以通过哈希运算次数和布隆缓存数组长度和插入数据数量计算出来。
布隆缓存建议我们多做几次哈希运算,即多存几个缓存索引,文中默认创建3个。
我们代码中,向布隆缓存数组中插入了2000个数据,通过计算得出,最佳的哈希运算次数为7,即当插入数量为2000,布隆缓存数组长度为20000时,HashCount的最优值为7。
布隆缓存有很多场景可以应用,比如重复URL检测,黑名单验证,垃圾邮件过滤等等。
举个例子,爬虫在爬取网站之前,会先通过布隆过滤计算出该Url是否已经爬取过,再确定是否发起Http请求。
关于缓存穿透、缓存击穿、缓存雪崩
缓存穿透是指缓存和数据库中都没有的数据,这时用户不断的发起这样的请求,会对数据库和缓存造成比较大的压力。
解决方案:增加更多,更有效的数据校验,让这些请求在进入查询前被拦截。将缓存和数据库中都没有的数据写入缓存,并设置一个较短的有效期,用来防止该请求多次进入到数据库。
缓存击穿是指缓存中的数据正好到期,然后又突然出现大量该数据的访问。导致大量请求直接发送到数据库。
解决方案:对数据进行热点标记,然后对热点数据进行特殊有效期设置。对普通数据进行有效期延长处理,比如被请求过一次,加长固定时间的有效期。
缓存雪崩与缓存击穿的意思类似,区别在于,缓存击穿指的是只有一条数据直接请求数据库,而雪崩指的是很多这样的数据直接请求数据库。
解决方案:缓存数据库分布式部署。
布隆缓存因为存在误判,所以不能用于百分之百定位数据的场景,但如果该场景可以容错,那布隆缓存将大大提升性能。
----------------------------------------------------------------------------------------------------
到此,到此布隆过滤就已经介绍完了。
代码已经传到Github上了,欢迎大家下载。
Github地址: https://github.com/kiba518/BloomFilter_Kiba
----------------------------------------------------------------------------------------------------
注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!
Recommend
-
76
作者:Soroush Khanlou, 原文链接 ,原文日期:2018-09-19 译者: WAMaker ;校对:
-
57
为什么引入 我们的业务中经常会遇到穿库的问题,通常可以通过缓存解决。 如果数据维度比较多,结果数据集合比较大时,缓存的效果就不明显了。 因此为了解决穿库的问题,我们引入Bloom Filter。 我们先看看一般业务缓...
-
56
-
59
为了解决布隆过滤器不能删除元素的问题,布谷鸟过滤器横空出世。论文《Cuckoo Filter:Better Than Bloom》作者将布谷鸟过滤器和布隆过滤器进行了深入的对比。相比布谷鸟过滤器而言布隆过滤器有以下不足:查询性能弱、空间利用效率低、不支持反向操
-
60
布隆过滤器是什么? 布隆过滤器可以理解为一个不怎么精确的 set 结构,当你使用它的 contains 方法判断某个对象是否存在时,它可能会...
-
6
布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。 它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困...
-
15
为什么需要布隆过滤器 想象一下遇到下面的场景你会如何处理: 手机号是否重复注册 用户是否参与过某秒杀活动 伪造请求大量 id 查询不存在的记录,此时缓存未命中,如何避免缓存穿透 针对以上问...
-
10
本文将以 C# 语言来实现一个简单的布隆过滤器,为简化说明,设计得很简单,仅供学习使用。 感谢@时总百忙之中的指导。 布隆过滤器简介 布隆过滤器(Bloo...
-
5
布隆过滤器(Bloom Filter)是一个基于Hash的概率性的数据结构,它是由一个很长的二进制数组组成,用来检查一个元素可能存在集合中,和一定不存在集合中; 它的优点是空间效率高,但是有一定false positive(假阳性:元素不在集合中,但是布隆过滤器显示在集...
-
11
C++进阶(位图+布隆过滤器的概念和实现+海量数据处理) ...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK