• Redis基于布隆过滤器解决缓存穿透问题(15)


    1.布隆过滤器基本介绍

    布隆过滤器适用于判断某个数据是否在集合中存在,可能存在一定的误判, Bloom Filter基本实现原理采用位数组与联合函数一起实现;实现的原理采用二进制向量数组和随机映射hash函数。
    布隆过滤器为什么会产生冲突 ,会根据key计算hash值,可能与布隆过滤器中存放的元素hash产生冲突都是为1,布隆可能会产生误判可能存在。
    如何解决这个问题,可以将二进制数组长度设置比较大,可以减少布隆误判的概率。
    【适合的场景】

    1. 防止缓存穿透直接访问数据库
    2. 判断用户是否阅读过某一个视频或文章;类似抖音,快手,可能误判,但是不会看到重复的内容
    3. 做黑名单过滤,针对不同的用户是否存在白名单和黑名单,可能误判,但一定程度可以解决问题等等

    2.布隆过滤器的优缺点

    优点
    1. 支持海量数据场景下高效的判断元素是否存在
    2. 空间占用极小,因为本身不存储数据而是用比特位表示数据是否存在,某种程度有保密的效果。

    缺点
    1. 不存储数据本身,所以只能添加但不可以删除,因为删除会导致误判率增加
    2. 由于存在hash碰撞,不一定百分百判断准确,存在一定误差

    3.布隆过滤器的原理

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

    简单来说就是准备一个长度为 m 的位数组并初始化所有元素为 0,用 k 个散列函数对元素进行 k 次散列运算跟 len(m)取余得到 k 个位置并将 m 中对应位置设置为 1。
    在这里插入图片描述

    4.缓存穿透问题

    缓存穿透是指使用不存在的key进行大量的高并发查询,导致缓存无法命中,每次请求都要都要穿透到后端数据库查询,使得数据库的压力非常大,甚至导致数据库服务卡死;
    应对的方案:

    1. 对我们的服务接口api实现限流、用户授权、黑名单和白名单拦截;
    2. 从缓存和数据库都查询不到结果的话,将数据库空值结果缓存到Redis中;设置合理过期时间(如:5s)避免使用同一个id对数据库攻击。
      如果黑客真的在攻击的情况下,随机成id肯定是不一样的,可采用布隆过滤器。
    3. 布隆过滤器
    <dependency>
        <groupId>com.google.guavagroupId>
        <artifactId>guavaartifactId>
        <version>32.1.2-jreversion>
    dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class BlongTest {
        /**
         * 在布隆中存放100万条数据
         */
        private static Integer size = 1000000;
    
        public static void main(String[] args) {
            BloomFilter<Integer> integerBloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, 0.01);
            for (int i = 0; i < size; i++) {
                integerBloomFilter.put(i);
            }
            // 从布隆中查询数据是否存在
            ArrayList<Integer> strings = new ArrayList<>();
            for (int j = size; j < size + 10000; j++) {
                if (integerBloomFilter.mightContain(j)) {
                    strings.add(j);
                }
            }
            System.out.println("误判数量:" + strings.size());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    5.解决Redis缓存穿透问题

    public static BloomFilter<Integer> integerBloomFilter = null;
    
    @RequestMapping("/getOrder")
    public OrderEntity getOrder(Integer orderId) {
        if (integerBloomFilter != null) {
            if (!integerBloomFilter.mightContain(orderId)) {
                System.out.println("从布隆过滤器中检测到该key不存在");
                return null;
            }
        }
    
        // 1.先查询Redis中数据是否存在
        OrderEntity orderRedisEntity = (OrderEntity) redisTemplateUtils.getObject(orderId + "");
        if (orderRedisEntity != null) {
            System.out.println("直接从Redis中返回数据");
            return orderRedisEntity;
        }
        // 2. 查询数据库的内容
        System.out.println("从DB查询数据");
        OrderEntity orderDBEntity = orderMapper.getOrderById(orderId);
        if (orderDBEntity != null) {
            System.out.println("将Db数据放入到Redis中");
            redisTemplateUtils.setObject(orderId + "", orderDBEntity);
        }
        return orderDBEntity;
    }
    
    @RequestMapping("/dbToBulong")
    public String dbToBulong() {
        List<Integer> orderIds = orderMapper.getOrderIds();
        integerBloomFilter = BloomFilter.create(Funnels.integerFunnel(), orderIds.size(), 0.01);
        for (int i = 0; i < orderIds.size(); i++) {
            integerBloomFilter.put(orderIds.get(i));
        }
        return "success";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    计算布隆过滤器在线网址:布隆过滤计算器
    在这里插入图片描述
    Guava 提供的布隆过滤器的实现还是很不错的,但是它有一个重大的缺陷就是只能单机使用,而现在互联网一般都是分布式的场景。为了解决这个问题就需要用到Redis中的布隆过滤器。

    参考:详解布隆过滤器的原理和实现

  • 相关阅读:
    掌握docker这几招,你也能搞云计算了
    如何设置HTTP代理服务器??
    ROS1云课→11曲线绘制
    Python中遍历列表remove漏删解决方案
    MySQL中datetime、date和timestamp的区别
    15.使用ref比reactive更好的几种场景
    性能测试知多少---性能分析与调优的原理
    IT廉连看——Uniapp——Uniapp生命周期
    c语言使用fdk_aac库对aac音频解码为pcm
    python---切片
  • 原文地址:https://blog.csdn.net/qq_34846877/article/details/126843874