• Redis实战-BloomFilter


    1. 简介

    布隆过滤器是防止缓存穿透的方案之一。布隆过滤器主要是解决大规模数据下不需要精确过滤的业务场景,如检查垃圾邮件地址,爬虫URL地址去重, 解决缓存穿透问题等。

    布隆过滤器:在一个存在一定数量的集合中过滤一个对应的元素,判断该元素是否一定不在集合中或者可能在集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难

    想详细了解的,可以查看我的另一篇博客Redis-缓存穿透/击穿/雪崩

    2. guava 实现

    google的guava工具类已经帮我们造好了轮子,通过实例来感受一下。

    2.1 导入依赖

    <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
       <version>30.1.1-jre</version>
    </dependency>
    

    2.2 BloomFilterTest

    import com.google.common.hash.BloomFilter;
    import com.google.common.hash.Funnels;
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * 布隆过滤器简单实现
     * @author ludangxin
     * @date 2021/8/16
     */
    @Slf4j
    public class BloomFilterTest {
       /**
        * 预计要插入元素个数
        */
       private static final int SIZE = 1000000;
       /**
        * 误判率
        */
       private static final double FPP = 0.01;
       /**
        * 布隆过滤器
        */
       private static final BloomFilter<Integer> BLOOMFILTER = BloomFilter.create(Funnels.integerFunnel(), SIZE, FPP);
    
       public static void main(String[] args) {
          //插入数据
          for (int i = 0; i < 1000000; i++) {
             BLOOMFILTER.put(i);
          }
          int count = 0;
          // 过滤判断
          for (int i = 1000000; i < 3000000; i++) {
             if (BLOOMFILTER.mightContain(i)) {
                count++;
                log.info(i + "误判了");
             }
          }
          log.info("总共的误判数:" + count);
       }
    }
    

    2.3 启动测试

    如上代码,我们设置了0.01的误差,过滤判断时从1000000到3000000,误判了2 * 20000000 ≈ 20339 符合预期。

    .....
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999004误判了
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999045误判了
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999219误判了
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999699误判了
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999753误判了
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999838误判了
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999923误判了
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 2999928误判了
    21:40:21.529 [main] INFO com.ldx.redisson.controller.BloomFilterTest - 总共的误判数:20339
    

    2.4 小节

    guava的工具包虽然好用,但是数据集是存储在jvm中的,分布式环境下依然没法使用。

    3. redisson 实现

    3.1 导入依赖

    <dependency>
       <groupId>org.redisson</groupId>
       <artifactId>redisson-spring-boot-starter</artifactId>
       <version>3.16.1</version>
    </dependency>
    

    3.2 BloomFilterWithRedisson

    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.redisson.api.RBloomFilter;
    import org.redisson.api.RedissonClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * redisson 布隆过滤器实现
     *
     * @author ludangxin
     * @date 2021/8/16
     */
    @Slf4j
    @RestController
    @RequestMapping("bloomFilter")
    @RequiredArgsConstructor
    public class BloomFilterWithRedisson {
       private final RedissonClient redissonClient;
    
       /**
        * 预计要插入元素个数
        */
       private static final long SIZE = 1000000L;
       /**
        * 误判率
        */
        private static final double FPP = 0.01;
    
       /**
        * 自定义布隆过滤器的 key
        */
       private static final String BLOOM_FILTER_KEY = "bloomFilter";
    
       /**
        * 向布隆过滤器中添加数据, 模拟向布隆过滤器中添加10亿个数据
        */
       @GetMapping
       public void filter() {
         // 获取布隆过滤器
          RBloomFilter<Integer> bloomFilter = redissonClient.getBloomFilter(BLOOM_FILTER_KEY);
          // 初始化,容量为100万, 误判率为0.01
          bloomFilter.tryInit(SIZE, FPP);
          // 模拟向布隆过滤器中添加100万个数据
          for (int i = 0; i < SIZE; i++) {
              bloomFilter.add(i);
          }
          int count = 0;
          // 过滤判断
          for (int i = 1000000; i < 3000000; i++) {
             if (bloomFilter.contains(i)) {
                count++;
                log.info(i + "误判了");
             }
          }
          log.info("size:" + bloomFilter.getSize());
          log.info("总共的误判数:" + count);
       }
    }
    

    3.3 启动测试

    由于机器性能有限,又是单机环境,所以程序没有跑完。

    但由此也可以看出,基于redis的布隆过滤器虽然解决了分布式问题,但是性能和guava bloomfilter没法比。

  • 相关阅读:
    .net jquery ajax应用(后台)
    .net jquery ajax应用(前端)
    echarts 添加Loading 等待。
    js将数字转换为带有单位的中文表示
    关于Pre-bound JDBC Connection found! HibernateTransactionManager does not 异常小结
    java 并发容器一之ConcurrentHashMap(基于JDK1.8)
    java 并发容器一之BoundedConcurrentHashMap(基于JDK1.8)
    23中java设计模式(1)-- 策略模式
    解决Eclipse自动补全变量名的问题
    Tomcat+Jenkins+SonarQube+SVN+Maven 集成自动化环境搭建(Windows10环境下)
  • 原文地址:https://www.cnblogs.com/ludangxin/p/15150254.html
Copyright © 2020-2023  润新知