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

布隆过滤器是一种空间效率极高的概率型数据结构,用于判断一个元素是否在一个集合中。它通过多个哈希函数将元素映射到位数组,存在一定的误判率。误判率与位数组长度和哈希函数数量有关,误判率越低,占用空间越大。在缓存穿透问题中,布隆过滤器可以有效防止无效查询,减少数据库压力。本文通过实例展示了布隆过滤器的误判现象及其内存占用情况,并讨论了如何根据实际需求选择合适的误判率。
摘要由CSDN通过智能技术生成

布隆过滤器介绍

巴顿.布隆于一九七零年提出,布隆过滤器中有一个很长的二进制向量(位数组)一系列随机函数 (哈希) 空间效率和查询效率高存在一定的误判率

布隆过滤器原理

布隆过滤器(Bloom Filter)的核心实现是一个超大的位数组和几个哈希函 数。假设位数组的长度为m,哈希函数的个数为k

以上图为例,具体的操作流程:假设集合里面有3个元素{x, y, z},哈希函 数的个数为3。首先将位数组进行初始化,将里面每个位都设置位0。对于 集合里面的每一个元素,将元素依次通过3个哈希函数进行映射,每次映射 都会产生一个哈希值,这个值对应位数组上面的一个点,然后将位数组对 应的位置标记为1。查询W元素是否存在集合中的时候,同样的方法将W通 过哈希映射到位数组上的3个点。如果3个点的其中有一个点不为1,则可以 判断该元素一定不存在集合中。反之,如果3个点都为1,则该元素可能存 在集合中。注意:此处不能判断该元素是否一定存在集合中,可能存在一 定的误判率。可以从图中可以看到:假设某个元素通过映射对应下标为4, 5,6这3个点。虽然这3个点都为1,但是很明显这3个点是不同元素经过哈 希得到的位置,因此这种情况说明元素虽然不在集合中,也可能对应的都 是1,这是误判率存在的原因。

布隆过滤器添加元素原理

将要添加的元素给k个哈希函数,得到对应于位数组上的k个位置,将这k个位置设为1

布隆过滤器查询元素原理

将要查询的元素给k个哈希函,得到对应于位数组上的k个位置,如果k个位置有一个为0,则肯定不在集合中,如果k个位置全部为1,则可能在集合中

演示布隆过滤器误判问题

(1) 新建一个maven工程,引入guava包,可以自行选取版本

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>x.x</version>
    </dependency>
</dependencies>

(2)  测试一个元素是否属于一个百万元素集合所需耗时

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.util.ArrayList;


/**
 * @program: demo
 * @description: 布隆过滤器误差演示
 * @author: 老王
 * @create: 2022-02-18 17:53
 **/
public class Test {
    private static int size = 1000000;

    private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(),size);

    public static void main(String[] args) {
        //模拟从0~1000000以此存放在过滤器中
        for(int i = 0;i < size;i++){
            bloomFilter.put(i);
        }

        ArrayList<Integer> integers = new ArrayList<>();

        //模拟新的数字在过滤器中进行比较判定
        for (int i = size+10000; i < size+20000; i++) {
            if(bloomFilter.mightContain(i)){
                integers.add(i);
            }
        }

        System.out.println("误判的数量:" +integers.size());
    }
}

输出结果如下

误判对数量:330

如果上述代码所示,我们故意取10000个不在过滤器里的值,却还有330个 被认为在过滤器里,这说明了误判率为0.03.即,在不做任何设置的情况 下,默认的误判率为0.03。

下面上源码来证明:

 接下来我们来看一下,误判率为0.03时,底层维护的bit数组的长度如下图所示

占用内存为:7298440

将bloomfilter的构造方法改为

private static BloomFilter bloomFilter=BloomFilter.create(Funnels.integerFunnel(), size,0.01); 

即,此时误判率为0.01。在这种情况下,底层维护的bit数组的长度如下图所示

占用内存为:9585058

由此可见,误判率越低,则底层维护的数组越长,占用空间越大。因此,在使用布隆过滤器时,误判率实际取值,根据服务器所能够承受的负载来决定,而不是随意决定。

布隆过滤器用户解决缓存穿透

将所有可能存在的数据缓存放到布隆过滤器中,当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉。

redis伪代码如下:

String get(String key) {
    String value = redis.get(key); //先从缓存获取。
    if (value == null) { //缓存没有命中
        if(!bloomfilter.mightContain(key)){//查看布隆过滤器钟是否存在
            return null;
        }else{
            value = db.get(key); //查询数据库
            redis.set(key, value);
        }
    }
    return value;
}

可以参照此方案根据需求改写应用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值