缓存穿透-布隆过滤器
⭐⭐⭐⭐⭐⭐
Github主页👉https://github.com/A-BigTree
笔记链接👉https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐
Spring专栏👉https://blog.csdn.net/weixin_53580595/category_12279588.html
SpringMVC专栏👉https://blog.csdn.net/weixin_53580595/category_12281721.html
Mybatis专栏👉https://blog.csdn.net/weixin_53580595/category_12279566.html
如果可以,麻烦各位看官顺手点个star~😊
如果文章对你有所帮助,可以点赞👍收藏⭐支持一下博主~😆
前言
在讲缓存穿透时,讲到了缓存空对象的方案,但缓存空对象遇到的两个问题:
- 如果是网络恶意攻击(每次key不一样,且数据库不存在),缓存占用了更多的内存;
解决方案:
缓存空对象要考虑到缓存时间的设置。这时候设置一个较短的过期时间(通常设定的缓存过期为60秒),就会自动剔除这些键。
- 如果过期时间设置的过大,数据库在此期间正好添加了该数据,就会出现数据不一致场景;
解决方案:
通过消息系统或者其它方式来清除缓存中的空对象。
而另一种方式就是使用 布隆缓存器!
布隆缓存器原理
布隆过滤器由一个很长且初值都为0的二进制(bit)数组和N个哈希函数组成,可以用来快速判断某个数据是否存在。当数据写入数据库时,布隆过滤器会通过三个操作完成标记:
- 使用N个hash函数,分别计算这个数据的hash值,得到N个hash值。
- 把这N个hash值对二进制数组的长度取模,得到每个hash值在数组中的位置,把对应位置设置为1。
- 如果数据不存在,那么就没用使用布隆过滤器标记过数据,那么,bit数组对应的bit位为零。只要二进制数组中这N个位置有一个不为1,就表明布隆过滤器就没标记过该数据。
反过来说,如果通过哈希函数算出来的值,对应的地方都是1,那么我们能够肯定的得出:这个数据一定存在于这个布隆过滤器中吗?
答案是否定的,因为多个不同的数据通过hash函数算出来的结果是会有重复的,所以会存在某个位置是别的数据通过hash函数置为的1。
我们可以得到一个结论:布隆过滤器可以判断某个数据一定不存在,但是无法判断一定存在。
举例
默认位数组:[0,0,0,0,0,0]
比方说有个已知key的下标是0,2,5,那么对应位数组:[1,0,1,0,0,1]
判断某个未知key存不存在的时候,假设我们计算出来的下标是0,2,4,那么对应位数组:[1,0,1,0,1,0]
,此时位数组内5对应下标值为0,而已知key位数组的5对应下标位1,说明这两个一定不是同一个key。
相反,如果某个key计算出来的下标为[1,0,1,0,0,1]
,只能说这个key可能存在,因为这个位置可能是其它key计算出来的;
优缺点
- 优点:优点很明显,二进制组成的数组,占用内存极少,并且插入和查询速度都足够快。
- 缺点:随着数据的增加,误判率会增加;还有无法判断数据一定存在;另外还有一个重要缺点就是无法删除数据。
我们可以使用Redis的bitmap来实现简单的布隆过滤器,bitmap支持2^32大小,对应到内存也就是512MB,可以放下2亿左右的数据,性能高,空间占用率及小,省去了大量无效的数据库连接。
解决缓存击穿的问题时,当把数据写入数据库,使用布隆过滤器做标记。当缓存消失后,在去数据库查询之前,通过查询布隆过滤器判断数据是否存在,如果不存在,就不查询数据库。