缓存穿透

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qmqm011/article/details/88801776

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。解决办法有缓存空对象和使用布隆过滤器。

一、缓存空数据

如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

缓存空对象会有两个问题:

第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。

第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

二、使用布隆过滤器

2.1 什么是布隆过滤器

布隆过滤器(Bloom Filter)是一个占用空间很小、效率很高的数据结构,它由一个bit数组和一组Hash算法构成,可用于判断一个元素一定不存在或者可能存在。

2.2 原理

讲述布隆过滤器的原理之前,我们先思考一下,通常判断某个元素是否存在用的是什么?应该大多数人都会使用 HashMap 吧,确实可以将值映射到 HashMap 的 Key,然后可以在 O(1) 的时间复杂度内返回结果,效率很高。但是 HashMap 的实现也有缺点,例如存储容量占比高,考虑到负载因子的存在,通常空间是不能被用满的(默认负载因子是0.75,也就是存储75个元素,至少需要100个空间,还可能产生碰撞),而一旦你的值很多例如上亿的时候,那 HashMap 占据的内存大小就变得很可观了。

2.2.1 布隆过滤器的数据结构

布隆过滤器初始化状态是一个全为0的bit数组:

如果我们要映射一个值到布隆过滤器中,需要使用多个不同的哈希函数生成多个哈希值,并将每个哈希函数生成的哈希值指向的bit位置 1。例如,值"baidu"和三个不同的哈希函数分别生成了哈希值 1、4、7,如下图所示:

如果现在再存一个值"tencent",哈希函数分别返回 3、4、8,如下图所示:

值得注意的是,"baidu"和"tencent"两个值的哈希函数都指向了4这个 bit 位,因此它被覆盖了。

现在如果我们想查询 “dianping” 这个值是否存在,哈希函数返回了 1、5、8三个值,结果我们发现 5 这个 bit 位上的值为 0,说明没有任何一个值映射到这个 bit 位上,因此我们可以很确定地说 “dianping” 这个值不存在。而如果我们需要查询 “baidu” 这个值是否存在的话,哈希函数必然会返回 1、4、7,然后我们检查发现这三个 bit 位上的值均为 1,那么我们可以说 “baidu” 存在了么?答案是不可以,只能是 “baidu” 这个值可能存在。这是为什么呢?答案跟简单,因为随着增加的值越来越多,被置为 1 的 bit 位也会越来越多,这样即使某个值没有被存储过,但是万一哈希函数返回的三个 bit 位都被其他值置为了 1 ,那么程序还是会判断这个值存在。

2.2.2 是否可以删除

目前我们知道布隆过滤器可以支持 add 和 isExist 操作,那么 delete 操作可以么?答案是不可以,例如上图中的 bit 位 4 被两个值共同覆盖的话,一旦你删除其中一个值例如 “tencent” 而将其置为 0,那么下次判断另一个值例如 “baidu” 是否存在的话,会直接返回 false,而实际上你并没有删除它。

如何解决这个问题呢?答案是计数删除。但是计数删除需要存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。这样的话,增加一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0。

2.2.3 哈希函数个数和bit数组长度

既然布隆过滤器要靠多个哈希函数将元素映射到数组中,那么应该选择几个哈希函数才能使元素查询时的错误率降到最低呢?如果哈希函数个数太多,那么对于一个不属于集合的元素进行查询的时候得到0的概率就大;如果哈希函数个数少,那么数组中的0就多。为了得到最优的哈希函数个数,可以通过如下公式计算:

下面看看,在不超过一定错误率的情况下,布隆过滤器需要多少位才能表示全集中任意n个元素。假设全集中共有u个元素,允许的最大错误率为c,则位数组m:

 

参考资料:

https://www.jianshu.com/p/2104d11ee0a2

https://blog.csdn.net/tianyaleixiaowu/article/details/74721877

https://blog.csdn.net/tianyaleixiaowu/article/details/74739827

 

猜你喜欢

转载自blog.csdn.net/qmqm011/article/details/88801776