zoukankan      html  css  js  c++  java
  • 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没法比。

  • 相关阅读:
    VB.Command()的参数
    XAMPP 启动mysql报错 InnoDB: Error: could not open single-table tablespace file……
    在不安装Windows服务的情况下,如何进行调试或测试
    Java基础东西(按位操作运算)
    浅谈web应用的负载均衡、集群、高可用(HA)解决方案
    关于CSDN, cnblog, iteye和51cto四个博客网站的比较与分析
    bzoj2243[SDOI2011]染色
    洛谷P2740 [USACO4.2]草地排水Drainage Ditches
    bzoj4198[noi2015]荷马史诗
    矩阵快速幂模板(pascal)
  • 原文地址:https://www.cnblogs.com/ludangxin/p/15150254.html
Copyright © 2011-2022 走看看