布隆过滤器+缓存穿透

1.缓存穿透问题:

产生的原因:

​ 在高并发场景下,如果某一个key被高并发访问,没有被命中,出于对容错性考虑,会尝试去从后端数据库中获取,从而导致了大量请求达到数据库,而当该key对应的数据本身就是空的情况下,这就导致数据库中并发的去执行了很多不必要的查询操作,从而导致巨大冲击和压力

方案一:缓存空对象

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

方案二:单独过滤

对所有可能对应数据为空的key进行统一的存放,并在请求前做拦截,这样避免请求穿透到后端数据库。这种方式实现起来相对复杂(实现↓)

2.问题:

怎样在海量数据中判断某个元素是否存在

布隆过滤器(guava ) n个元素,使用m个hash函数

大量数据存储:位图+链表

误判率:0.03 原因(快速判断 hash碰撞)

原理:

​ 1.布隆过滤器认为该元素存在不一定存在。

​ 2.布隆过滤器认为该元素不存在就一定不存在。

1.依赖

		<dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>21.0</version>
        </dependency>

布隆过滤器guava实现

package com.song.bloom;
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

import java.text.NumberFormat;
import java.util.*;

public class BloomFilterDemo {
    private static  final  int  insertions=100000;

    public static void main(String[] args) {
        //初始化一个存储string数据的布隆过滤器,初始化大小为100m
        //默认误判率是0.03, 0.001 为误判率
        BloomFilter<String> bf = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), insertions,0.001);
        //用于存放所有实际存在的key,判断key是否存在
        Set<String>  sets = new HashSet<>(insertions);

        //用于存放所有实际存在的key,可以取出使用
        List<String> lists= new ArrayList<>(insertions);

        //向三个容器初始化100w个随机并且唯一的字符串
        for (int i = 0; i < insertions; i++) {
            String uuid = UUID.randomUUID().toString();
            bf.put(uuid);
            sets.add(uuid);
            lists.add(uuid);

        }
        int  right=0; //正确判断的次数
        int  wrong=0; //错误判断的次数
        for (int i = 0; i < 10000; i++) {
            //可以别被100整除的时候,取一个存在的数,否则随机生成一个uuid
            //0-10000之间,可以被100整除的数有100个(100的倍数)
            String data=i%100==0? lists.get(i/100):UUID.randomUUID().toString();
            /*
            mightContain()方法判断是否存在 
            */
            if (bf.mightContain(data)){
                if (sets.contains(data)){
                    //判断存在实际存在的时候,命中
                    right++;
                    continue;
        }
        //判断不存在的时候,错误
        wrong++;
    }
        }
        NumberFormat numberFormat = NumberFormat.getPercentInstance();
        numberFormat.setMaximumFractionDigits(2);  //最大小数位数
        float percent=(float)wrong/9900;
        float bingo=(float) (9900-wrong)/9900;
        System.out.println("在100w个元素中,判断100个实际存在的元素,布隆过滤器认为存在的:"+right);
        System.out.println("在100w个元素中,误判9900个实际不存在的元素,误认为存在的:"+wrong+""+",命中率:"+numberFormat.format(bingo)+",误判率:"+numberFormat.format(percent));

    }
}

源码解析:

错误率源码解析,可以修改

  @CheckReturnValue
    public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions) {
        return create(funnel, expectedInsertions, 0.03D);
    }

使用的hash算法

 @CheckReturnValue
    public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions, double fpp) {
        return create(funnel, expectedInsertions, fpp, BloomFilterStrategies.MURMUR128_MITZ_64);
    }

创建的位图大小

 @VisibleForTesting
    static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions, double fpp, BloomFilter.Strategy strategy) {
        Preconditions.checkNotNull(funnel);
        Preconditions.checkArgument(expectedInsertions >= 0L, "Expected insertions (%s) must be >= 0", new Object[]{expectedInsertions});
        Preconditions.checkArgument(fpp > 0.0D, "False positive probability (%s) must be > 0.0", new Object[]{fpp});
        Preconditions.checkArgument(fpp < 1.0D, "False positive probability (%s) must be < 1.0", new Object[]{fpp});
        Preconditions.checkNotNull(strategy);
        if (expectedInsertions == 0L) {
            expectedInsertions = 1L;
        }
	//位图的容量,是布隆理论计算出来的
        long numBits = optimalNumOfBits(expectedInsertions, fpp);
        int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);

        try {
            return new BloomFilter(new BitArray(numBits), numHashFunctions, funnel, strategy);
        } catch (IllegalArgumentException var10) {
            throw new IllegalArgumentException("Could not create BloomFilter of " + numBits + " bits", var10);
        }
    }
100w 数据大约生成 7298440 bit =0.8700418 m
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值