20201102 布隆过滤器解决缓存穿透

 

不同数据类型的布隆过滤器: Integer,Long等

两个步骤:

1)将数据放入bloom filter中;

2)判断数据是否已在bloom filter中;

 

基于url级别的权限判断,判断访问权限是否存在可用此方案解决, ip黑名单;

字节数组,元素是0或者1.

添加元素的时候,判断元素是否存在的时候。

错误率越大,所需空间和时间越小,错误率越小,所需空间和时间约大(可以自己定义错误率)。

 

它可以通过一个Hash函数将一个元素映射成一个位阵列(Bit array)中的一个点。这样一来,我们只要看看这个点是不是1就可以知道集合中有没有它了。这就是布隆过滤器的基本思想。

判断元素在不在一个集合里面,如果集合里面的元素非常大,这个判断过程是非常耗时的,而且集合占用空间也很大。

布隆过滤器存储空间和插入/查询时间都是常数。Hash函数相互之间没有关系,方便由硬件并行实现。布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势。

package com.demo.www.springbootdemo.crs.bloomfilter;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

/**
 * 测试布隆过滤器
 */
public class TestBloomFilter {
    
    //定义布隆过滤器的长度
    private static int total = 1000000;
    //创建布隆过滤器
    private static BloomFilter bloomFilter = BloomFilter.create(Funnels.integerFunnel(), total,0.0003);

    private static int index = 0;
    private static int count = 0;
    public static void main(String[] args) {
        for (int i = 0; i < total; i++) {
            //将数据添加到过滤器中
            bloomFilter.put(i);
        }

        //判断数据是否存在?
        for (int i = 0; i < total; i++) {
            if (!bloomFilter.mightContain(i)) {
                index++;
                System.out.println("有数据没检测到" + i);
            }
        }
        System.out.println("是否能够识别过滤器中数据:"+index);
        //数据全部存在
        //测试另外的10000数据,看看过滤器的误杀情况?现在是都不存在与过滤器中。

        for (int i = total; i < total+10000; i++) {
            if ( bloomFilter.mightContain(i)){
                count++;
            }
        }
        System.out.println("误判的数据量"+count);  //286个数据,本来不存在,但是确判定存在了。

        //1,遍历这一百万个在过滤器中的数时,都被识别出来了。
        //2,一万个不在过滤器中的数,误伤了320个,错误率是0.03左右。

        //某个判断的执行时间
        long startTime = System.nanoTime(); // 获取开始时间
        //判断这一百万个数中是否包含29999这个数
        if (bloomFilter.mightContain(29999)) {
            System.out.println("命中了");
        }
        long endTime = System.nanoTime();   // 获取结束时间
        System.out.println("程序运行时间: " + (endTime - startTime) + "纳秒");
        //结果是1毫秒都不到即可判断出是否存在,所占用的空间也比较小。
    }
}

 错误率,所占用内存空间,执行hash的次数:

BloomFilter概念

它是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

 

BloomFilter原理

当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。

Bloom Filter使用了k个哈希函数,每个字符串跟k个bit对应。从而降低了冲突的概率。

 

BloomFilter缺点

bloom filter之所以能做到在时间和空间上的效率比较高,是因为牺牲了判断的准确率、删除的便利性

1,存在误判,可能要查到的元素并没有在容器中,但是hash之后得到的k个位置上值都是1。如果bloom filter中存储的是黑名单,那么可以通过建立一个白名单来存储可能会误判的元素。

2,删除困难。一个放入容器的元素映射到bit数组的k个位置上是1,删除的时候不能简单的直接置为0,可能会影响其他元素的判断。可以采用CountingBloomFilter

 

BloomFilter实现

Guava中提供了一种Bloom Filter的实现。

在使用bloom filter时,绕不过的两点:1是预估数据量n以及期望的误判率fpp,2是hash函数的选取以及bit数组的大小。

对于一个确定的场景,我们预估要存的数据量为n,期望的误判率为fpp,然后需要计算我们需要的Bit数组的大小m,以及hash函数的个数k,并选择hash函数.

(1)Bit数组大小选择

(2)哈希函数选择

 

布隆过滤器的设计

布隆过滤器思路比较简单,但是对于布隆过滤器的随机映射函数设计,需要计算几次,向量长度设置为多少比较合适,这个才是需要认真讨论的。

如果向量长度太短,会导致误判率直线上升。

如果向量太长,会浪费大量内存。

如果计算次数过多,会占用计算资源,且很容易很快就把过滤器填满。

 

缓存穿透(每次查询都会直接打到DB)

用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值