神奇的布隆过滤器

一、缓存穿透

项目中的热点数据我们一般会放在 redis 中,在数据库前面加了一层缓存,减少数据库的访问,提升性能。但如果,请求的 key 在 redis 中并不存在,那请求还是会抵达数据库,这就叫缓存穿透。

我们无法避免缓存穿透,因为数据库中的数据要全部放到 redis 中不太现实,也不可能保证数据库数据和 redis 中的数据做到实时同步。但我们可以避免高频的缓存穿透。

避免高频缓存穿透的办法:

  • 做好参数检验,对于一些非法参数直接挡掉,比如 id 为负数的请求直接挡掉;

  • 缓存无效的 key,比如某次请求的 key 在数据库中不存在,那就将其缓存到 redis 并设置过期时间,但是这种办法不好,假如黑客每次请求都用不同的 key,那 redis 中的无用数据就会很多;

  • 使用布隆过滤器;

二、布隆过滤器

1. 过滤器的作用

上面说了,如果大量不存在的 key 请求过来,还是会直接请求到数据库,如果我们能在请求数据库之前判断这个 key 在数据库到底存不存在,不存在就直接返回相关错误信息,那就可以解决缓存穿透的问题。

如何在不请求数据库的前提下判断这个 key 在数据库中存不存在呢?这就需要用到过滤器。难不成又要将数据库的所有数据缓存到过滤器中吗?当然不是,如果这样,那和将所有 key 缓存到 redis 就没啥区别了。接下来看看布隆过滤器是怎么做的。

2. 布隆过滤器原理

布隆过滤器使用了布隆算法来存储数据,明确一点, 布隆算法存储的数据不是 100% 准确的,即布隆过滤器认为这个 key 存在,实际上它也有可能不存在,如果它认为这个key 不存在,那么它一定不存在。 布隆算法是通过一定的错误率来换取空间的。

布隆算法通过 bit 数组 来标识 key 是否存在。怎么做的呢?key 经过 hash 函数的运算,得到一个数组的下标,然后将对应下标的值改成1,1就表示该 key 存在。这个 hash 函数要满足的条件有:

  • 对 key 计算的结果必须在 [0, bitArray.length - 1] 之间;

  • 计算出来的结果分布要足够散列;

因为要进行 hash 计算,所有布隆算法的错误率是由于 hash 碰撞导致的。所以降低 hash 碰撞的概率就可以降低错误率。怎么降低 hash 碰撞的概率呢?两种办法:

  • 加大数组的长度:数组长度更长,hash 碰撞的概率自然更小;

  • 增加 hash 函数的个数:假如 key 为 10 的数据,第一个 hash 函数计算出来的下标是 1,第二个 hash 函数计算出来的是 4,第三个 hash 函数计算出来的是 10,那么就要 1,4,10 这三个下标所对应的值都得是 1,才会认为 key 存在,故而也可以减少误判的情况。

3. 为什么要用 bit 数组

因为节省空间。1k = 1024byte = 1024 * 8 bit = 8192bit,即长度为8192的bit数组只需要1kb的空间。

4. 怎么用

业界大佬和民间大神已经造了很多轮子了,这里主要说三种,具体用法大家看一下相关 api 即会了。

  • 可以使用 guava 中的布隆过滤器;

  • 使用 hutools 工具包中的布隆过滤器;

  • redis 有 bitMap,也可以用作布隆过滤器,推荐使用 redisson 构造布隆过滤器;

三、hutools 中的布隆过滤器源码分析

这里带大家分析一下 hutools 中的布隆过滤器源码,看看人家怎么实现的。用法如下:

public static void main(String[] args) {
   
	BitMapBloomFilter bloomFilter = new BitMapBloomFilter(5);
	bloomFilter.add("aa");
	bloomFilter.add("bb");
	bloomFilter.add(
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值