布隆过滤器在redisson中的使用

布隆过滤器在redisson中的使用

数据库的数据是存储在磁盘上的,高速访问会存在性能问题,使用缓存中间件Redis,可以缓解数据访问的压力;同时数据库查询不到的数据会放在缓存中,并存入 NULL 值,降低数据库消耗;但是若是这样的NULL值过多则会降低缓存性能,什么方式能过滤掉这些无意义的查询,布隆过滤器由此而生

本质:

​ 布隆过滤器使用Bit-map(位图)进行标记,达到判断“一定不存在和可能存在”的目的

解决什么问题:

​ redis缓存穿透

基于redisson的BloomFilter的使用

1.引入redisson工具maven依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.12.3</version>
</dependency>

2.修改springboot配置文件

redisson:
  host:
    config: redis://192.168.152.129:6379
# slf4j日志配置
logging:
  # 配置级别
  #分包配置级别,即不同的目录下可以使用不同的级别
  level:
    com: debug
  # 在不指定路径,只指定输出日志的文件名,默认输出至当前项目下
  # 若指定,则会输出至指定目录下
  file:
    path: log\book.log

3.新建conf层

@Configuration
public class RedissonConf {//加载redisson配置
    @Autowired
    private Environment env;
    @Bean
    public RedissonClient redissonClient(){
        Config cfg=new Config();
        cfg.useSingleServer().
                setAddress(env.getProperty("redisson.host.config")).
                setKeepAlive(true);
        
        return Redisson.create(cfg);
    }
}

4.BloomFilter数值过滤

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class RedissonTest {
    //定义日志
    private static final Logger log= LoggerFactory.getLogger(RedissonTest.class);
    //定义操作Redisson的客户端实例
    @Autowired
    private RedissonClient redissonClient;
    @Test
    public void test1(){
        String key="MyBloom";
        Integer total=100000;
        RBloomFilter<Integer> bloomFilter=redissonClient.getBloomFilter(key);
        //初始化布隆过滤器
        bloomFilter.tryInit(total,0.01);//精度越高,消耗空间越大
        //生成元素
        for(int i=1;i<=total;i++){
            bloomFilter.add(i);
        }
        log.info("测试该布隆过滤器里面是否含有1:{}",bloomFilter.contains(1));
        log.info("测试该布隆过滤器里面是否含有-1:{}",bloomFilter.contains(-1));
        log.info("测试该布隆过滤器里面是否含有100:{}",bloomFilter.contains(100));
        log.info("测试该布隆过滤器里面是否含有10000:{}",bloomFilter.contains(10000));
    }
}

5.BloomFilter键值过滤

我们先建立dto层

@Data
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class BloomDto implements Serializable {
    private Integer id;
    private String msg;
}

然后查询

@Test
public void test2(){
    String key="MyBloom1";
    Integer total=1000;
    RBloomFilter<BloomDto> bloomFilter=redissonClient.getBloomFilter(key);
    //初始化布隆过滤器
    bloomFilter.tryInit(total,0.01);

    bloomFilter.add(new BloomDto(100,"北京"));
    bloomFilter.add(new BloomDto(101,"上海"));
    bloomFilter.add(new BloomDto(102,"深圳"));
    bloomFilter.add(new BloomDto(103,"武汉"));
    bloomFilter.add(new BloomDto(104,"哈尔滨"));

    log.info("该布隆过滤器是否包含数据(1,\"1\"):{}",bloomFilter.contains(new BloomDto(1,"1")));
    log.info("该布隆过滤器是否包含数据(1,\"北京\"):{}",bloomFilter.contains(new BloomDto(1,"北京")));
    log.info("该布隆过滤器是否包含数据(101,\"上海\"):{}",bloomFilter.contains(new BloomDto(101,"上海")));
    log.info("该布隆过滤器是否包含数据(104,\"哈尔滨\"):{}",bloomFilter.contains(new BloomDto(104,"哈尔滨")));
}

6.Bloomfltermap过滤

先建RMapDto

@Data
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class RMapDto implements Serializable {
    private Integer id;
    private String name;
}

查询

@Test
public void test3(){//map形式存储
    String key="MyBloom2";
    RMap<Integer,RMapDto> rmap=redissonClient.getMap(key);
    RMapDto dto1=new RMapDto(1,"map1");
    RMapDto dto2=new RMapDto(2,"map2");
    RMapDto dto3=new RMapDto(3,"map3");
    RMapDto dto4=new RMapDto(4,"map4");
    RMapDto dto5=new RMapDto(5,"map5");
    RMapDto dto6=new RMapDto(6,"map6");
    RMapDto dto7=new RMapDto(7,"map7");
    RMapDto dto8=new RMapDto(8,"map8");

    rmap.put(dto1.getId(),dto1);
    rmap.putIfAbsent(dto2.getId(),dto2);
    rmap.putIfAbsentAsync(dto3.getId(),dto3);
    rmap.putAsync(dto4.getId(),dto4);
    rmap.fastPut(dto5.getId(),dto5);
    rmap.fastPutIfAbsent(dto6.getId(),dto6);
    rmap.fastPutAsync(dto7.getId(),dto7);
    rmap.fastPutIfAbsentAsync(dto8.getId(),dto8);

    log.info("---往映射数据结构RMap中添加数据元素完毕---");
}

@Test
public void test4() {//map形式查询
    //String key="MyBloom1";
    //RMap<Integer,RMapDto> rmap=redissonClient.getMap(key);
	//此处若key并不存在会报错:channel: [id: 0xc0ad866d, L:/192.168.152.1:63613 - R:192.168.152.129/192.168.152.129:6379] command: (HLEN), params: [MyBloom1]
    String key="MyBloom2";
    RMap<Integer,RMapDto> rmap=redissonClient.getMap(key);
    Set<Integer> ss=rmap.keySet();
    Map<Integer,RMapDto> map=rmap.getAll(ss);
    log.info("元素列表:{} ",map);

    rmap.remove(6);//指定删除
    log.info("元素列表:{} ",rmap.getAll(ss));

    Integer is[] ={1,2,3};//快速删除
    rmap.fastRemove(is);
    log.info("元素列表:{} ",rmap.getAll(ss));
}

设置过期时间、异步存储

@Test
public void test5() {//map形式存储
    String key="MyBloom3";
    RMapCache<Integer,RMapDto> rmap=redissonClient.getMapCache(key);

    RMapDto dto1=new RMapDto(1,"map1");
    RMapDto dto2=new RMapDto(2,"map2");
    RMapDto dto3=new RMapDto(3,"map3");
    RMapDto dto4=new RMapDto(4,"map4");
    RMapDto dto5=new RMapDto(5,"map5");
    RMapDto dto6=new RMapDto(6,"map6");
    RMapDto dto7=new RMapDto(7,"map7");
    RMapDto dto8=new RMapDto(8,"map8");

    rmap.put(dto1.getId(),dto1);
    rmap.putIfAbsent(dto2.getId(),dto2,5, TimeUnit.SECONDS);
    rmap.putIfAbsentAsync(dto3.getId(),dto3);
    rmap.putAsync(dto4.getId(),dto4);
    rmap.fastPut(dto5.getId(),dto5,10,TimeUnit.SECONDS);
    rmap.fastPutIfAbsent(dto6.getId(),dto6);
    rmap.fastPutAsync(dto7.getId(),dto7);
    rmap.fastPutIfAbsentAsync(dto8.getId(),dto8);

    Set<Integer> ss=rmap.keySet();
    Map<Integer,RMapDto> map=rmap.getAll(ss);
    log.info("元素列表:{} ",map);

    try {
        Thread.sleep(5000);
        Set<Integer> ss1=rmap.keySet();
        Map<Integer,RMapDto> map1=rmap.getAll(ss1);
        log.info("5s元素列表:{} ",map1);

        Thread.sleep(5000);
        Set<Integer> ss2=rmap.keySet();
        Map<Integer,RMapDto> map2=rmap.getAll(ss2);
        log.info("又5s元素列表:{} ",map2);

    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
元素列表:{1=RMapDto(id=1, name=map1), 2=RMapDto(id=2, name=map2), 3=RMapDto(id=3, name=map3), 4=RMapDto(id=4, name=map4), 5=RMapDto(id=5, name=map5), 6=RMapDto(id=6, name=map6), 7=RMapDto(id=7, name=map7), 8=RMapDto(id=8, name=map8)} 
5s后元素列表:{1=RMapDto(id=1, name=map1), 3=RMapDto(id=3, name=map3), 4=RMapDto(id=4, name=map4), 5=RMapDto(id=5, name=map5), 6=RMapDto(id=6, name=map6), 7=RMapDto(id=7, name=map7), 8=RMapDto(id=8, name=map8)} 
又5s后元素列表:{1=RMapDto(id=1, name=map1), 3=RMapDto(id=3, name=map3), 4=RMapDto(id=4, name=map4), 6=RMapDto(id=6, name=map6), 7=RMapDto(id=7, name=map7), 8=RMapDto(id=8, name=map8)} 
2020-11-27 20:09:40.398  INFO 14896 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
Process finished with exit code 0

由最后的结果可见布隆过滤器的基本使用暂没出现什么问题

<think>好的,用户想了解如何在Java中使用Redisson实现布隆过滤器。我需要先回忆一下布隆过滤器的基本概念和Redisson的相关知识。布隆过滤器是一种概率型数据结构,用于判断一个元素是否可能存在于集合中,可以有效地防止缓存穿透问题。Redisson是一个Java的Redis客户端,提供了许多分布式数据结构,包括布隆过滤器。 接下来,我需要整理用户提供的引用内容。引用[1]和[3]提到了Redisson的RBloomFilter类,引用[2]展示了使用Jedis的示例,但用户更关心的是Redisson实现。引用[4]提到分片布隆过滤器的优化方法,可能需要考虑在示例中是否包含这部分内容,但用户主要请求的是基础教程和示例代码,所以分片可能作为优化部分提及。 用户需要教程、示例和代码,所以应该分步骤说明。首先,添加Redisson依赖,然后配置Redisson客户端,接着初始化布隆过滤器,添加元素和检查存在性。需要注意布隆过滤器的参数,如预期插入数量和误判率,这些参数会影响布隆过滤器的大小和哈希函数的数量。 需要确保代码示例正确,使用正确的类和方法。例如,Redisson的RBloomFilter需要指定名称、预期元素数量和误判概率。然后使用add方法添加元素,contains方法检查存在性。同时,要提醒用户布隆过滤器的特性,比如可能存在误判,删除元素困难,以及初始化后参数不能修改。 可能还需要比较Redisson实现与其他方法,比如引用[2]中的Jedis实现,指出Redisson的优势,如更简洁的API和自动管理底层细节。此外,引用[4]提到的分片优化可以作为性能优化建议的一部分,但用户的问题主要是基础实现,所以可能放在注意事项或优化建议部分。 最后,生成相关问题,帮助用户进一步学习,比如性能调优、误判率计算、与其他过滤器的比较等。要确保问题相关且有引导性,帮助用户深入理解布隆过滤器使用和优化。</think>### Redisson实现布隆过滤器教程 #### 一、实现步骤 1. **添加Redisson依赖** 在Maven项目中引入Redisson依赖: ```xml <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.17.7</version> <!-- 使用最新版本 --> </dependency> ``` 2. **配置Redisson客户端** 创建与Redis服务器的连接配置: ```java Config config = new Config(); config.useSingleServer().setAddress("redis://localhost:6379"); RedissonClient redisson = Redisson.create(config); ``` 3. **初始化布隆过滤器** 设置预期插入元素数量和误判率(默认0.03): ```java RBloomFilter<String> bloomFilter = redisson.getBloomFilter("userFilter"); bloomFilter.tryInit(1000000L, 0.01); // 参数:预期元素量,误判率 ``` 4. **添加元素与查询存在性** ```java bloomFilter.add("user:1001"); // 添加元素 boolean exists = bloomFilter.contains("user:1002"); // 检查存在性 ``` #### 二、完整代码示例 ```java import org.redisson.Redisson; import org.redisson.api.RBloomFilter; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class BloomFilterDemo { public static void main(String[] args) { // 1. 配置Redis连接 Config config = new Config(); config.useSingleServer().setAddress("redis://localhost:6379"); // 2. 创建客户端实例 RedissonClient redisson = Redisson.create(config); // 3. 初始化布隆过滤器(名称需唯一) RBloomFilter<String> bloomFilter = redisson.getBloomFilter("userFilter"); bloomFilter.tryInit(1000000L, 0.01); // 预期插入100万元素,1%误判率 // 4. 数据操作 bloomFilter.add("user:1001"); bloomFilter.add("user:1002"); System.out.println(bloomFilter.contains("user:1001")); // true System.out.println(bloomFilter.contains("user:9999")); // false // 5. 关闭连接 redisson.shutdown(); } } ``` #### 三、关键特性说明 1. **参数动态调整** 通过`tryInit()`设置的容量和误判率需在**首次初始化时确定**,后期不可修改[^3]。 2. **分布式特性** 所有客户端共享同一个Redis实例中的布隆过滤器状态,天然支持分布式环境[^1]。 3. **性能优化建议** - 分片存储:当数据量极大时采用多个布隆过滤器分片,降低单次操作延迟[^4] - 容量预估:初始容量建议设置为实际数据量的1.5-2倍 - 哈希优化:Redisson自动计算最优哈希函数数量 #### 四、典型应用场景 1. 缓存穿透防护(如商品ID预过滤) 2. 爬虫URL去重 3. 推荐系统内容排重
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值