缓存穿透-解决方案之-布隆过滤器

什么是缓存穿透?

出现Redis中不存在的缓存数据。

解决方案:

1:缓存一个空对象

对查询结果为空的对象也进行缓存,如果是集合,可以缓存一个空的集合(非 null ),如果是缓存单个对象,可以通过字段标识来区分。这样避免请求穿透到后端数据库。

同时,也需要保证缓存数据的时效性。这种方式实现起来成本较低,比较适合命中不高,但可能被频繁更新的数据。

2:单独过滤处理

对所有可能对应数据为空的 key 进行统一的存放,并在请求前做拦截,这样避免请求穿透到后端数据库。这种方式实现起来相对复杂,比较适合命中不高,但是更新不频繁的数据。

第二点其实就是可以用布隆过滤器来实现;

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。

如果还是不太好理解的话,就可以把布隆过滤器理解为一个set集合,我们可以通过add往里面添加元素,通过contains来判断是否包含某个元素。

布隆过滤器的优点:
    1:时间复杂度低,增加和查询元素的时间复杂为O(N),(N为哈希函数的个数,通常情况比较小)
    2:保密性强,布隆过滤器不存储元素本身
    3:存储空间小,如果允许存在一定的误判,布隆过滤器是非常节省空间的(相比其他数据结构如Set集合)
    
布隆过滤器的缺点:
    1:有点一定的误判率,但是可以通过调整参数来降低
        主要是判断不存在的,则一定不存在;判断存在的,大概率存在,但也有小概率不存在。
    2:无法获取元素本身
    3:很难删除元素

优点:优点很明显,二进制组成的数组,占用内存极少,并且插入和查询速度都足够快。
缺点:随着数据的增加,误判率会增加;还有无法判断数据一定存在;另外还有一个重要缺点,无法删除数据。

布隆过滤器有以下不足:查询性能弱、空间利用效率低、不支持反向操作(删除)以及不支持计数。
    查询性能弱是因为布隆过滤器需要使用多个 hash 函数探测位图中多个不同的位点,这些位点在内存上跨度很大,会导致 CPU 缓存行命中率低。
    
    空间效率低是因为在相同的误判率下,布谷鸟过滤器的空间利用率要明显高于布隆,空间上大概能节省 40% 多。
        不过布隆过滤器并没有要求位图的长度必须是 2 的指数,而布谷鸟过滤器必须有这个要求。
        从这一点出发,似乎布隆过滤器的空间伸缩性更强一些。
        
    不支持反向删除操作这个问题着实是击中了布隆过滤器的软肋。在一个动态的系统里面元素总是不断的来也是不断的走。
        布隆过滤器就好比是印迹,来过来就会有痕迹,就算走了也无法清理干净。
        比如你的系统里本来只留下 1kw 个元素,但是整体上来过了上亿的流水元素,
        布隆过滤器很无奈,它会将这些流失的元素的印迹也会永远存放在那里。
        随着时间的流失,这个过滤器会越来越拥挤,直到有一天你发现它的误判率太高了,不得不进行重建。

布隆过滤器:一种数据结构(bitmap),是由一串很长的二进制向量组成,可以将其看成一个二进制数组。既然是二进制,那么里面存放的不是0,就是1,但是初始默认值都是0。


*1.*添加数据*
当要向布隆过滤器中添加一个元素key时,我们通过多个hash函数,算出一个值,然后将这个值所在的方格置为1。

*2.如何判断是否存在
将这个新的数据通过上面自定义的几个哈希函数,分别算出各个值,然后看其对应的地方是否都是1,如果存在一个不是1的情况,那么我们可以说,该新数据一定不存在于这个布隆过滤器中。
反过来说,如果通过哈希函数算出来的值,对应的地方都是1,那么我们能够肯定的得出:这个数据一定存在于这个布隆过滤器中吗?
答案是否定的,因为多个不同的数据通过hash函数算出来的结果是会有重复的,所以会存在某个位置是别的数据通过hash函数置为的1。

我们可以得到一个结论:布隆过滤器可以判断某个数据一定不存在,但是无法判断一定存在。
 

存入过程:通过三个hash函数计算出三个哈希值,然后将三个值映射到数组中将0改成1。
查间过程:通过三个hash函数计算出查询数据的哈希值,然后检查布隆过滤器对应位置上的值是否为1,如果有一个不为1表示该值不存在,如果都为1表示该值可能存在。(查询时间复杂度为O(k),k为哈希函数个数)
删除过程:不能进行删除,因为会删除掉其他数据。
更新过程:也不能进行更新。

实现:(Guava)
调用谷歌的guava包的api。
缺点:guavah版实现主要问题在于无法支持集群环境。为了支持集群环境主要考虑通过redis setbit来实现BloomFilter。。

该方案最大的一个问题是布隆过滤器不支持反向删除操作,例如你的项目里活跃的key的数量只有1000w个,但是全部key数量有5000w个,那这5000w个key会全部存在布隆过滤器里!

直到某一天,你会发现这个过滤器太拥挤了,误判率太高,不得不进行重建!

为了解决上面布隆过滤器的问题,出现了一个增强版的布隆过滤器(Counting Bloom Filter),这个
过滤器的思路是将布隆过滤器的bitmap.更换成数组,当数组某位置被映射一次时就+1,当删除时
就-1,这样就避免了普通布隆过滤器删除数据后需要重新计算其余数据包Hash的问题,但是依日没
法避免误判。

升级版的布隆过滤器(Counting Bloom Filter)
    原理就是把位图的位 升级为计数器(Counter). 
        添加元素, 就给对应的Counter分别+1; 
        删除元素, 就给对应的Counter分别减一. 用多出几倍存储空间的代价, 来实现删除功能

https://zhuanlan.zhihu.com/p/462813998
https://blog.csdn.net/fengyuyeguirenenen/article/details/124191117

一行代码解决缓存击穿问题 - 掘金

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值