布隆过滤器用Redisson实现的例子

背景介绍

之前这边有写过关于布隆过滤器过滤器的安装使用,但是这次使用使用jrebloom来实现,
jrebloom目前只提供一个maven依赖供我们使用。
布隆过滤器用Redisson实现的例子_第1张图片

考虑到后续代码维护,bug的修复。使用redisson来做布隆过滤器是更加安全做法。
布隆过滤器用Redisson实现的例子_第2张图片
下面是关于布隆过滤器的使用:
布隆过滤器的原理、redis布隆过滤器的安装和使用

代码实现


下面使用Redisson对布隆过滤器进行的封装。
1、引入maven依赖


        
            org.redisson
            redisson
            3.13.1
        

2、关于redis的配置

redis配置:


#客户端超时时间单位是毫秒 默认是2000
redis.timeout=10000
#最大空闲数
redis.maxIdle=300
#连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal
#redis.maxActive=600
#控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
redis.maxTotal=2000
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
redis.maxWaitMillis=1000

redis.nodes=192.168.25.128:7000,192.168.25.128:7001,192.168.25.128:7002,192.168.25.128:7003,192.168.25.128:7004,192.168.25.128:7005,192.168.25.128:7006,192.168.25.128:7007

3、配置文件的书写

@Configuration
@PropertySource("classpath:conf/redis.properties")
public class RedisConfig {


    @Value("${redis.nodes}")
    private String clusterNodes;


    @Bean
    public RedissonClient getBloomFilter(){
        Config config = new Config();
        ClusterServersConfig clusterServersConfig = config.useClusterServers();
        String[] cNodes = clusterNodes.split(",");
        //分割出集群节点
        for (String node : cNodes) {
            clusterServersConfig.addNodeAddress("redis://" + node);

        }
        return Redisson.create(config);
    }


}

4、service的的代码

public interface RedissonBloomFilterService {
    /**
     * 初始化一个布隆过滤器
     *
     * @param key        key
     * @param expireDate 过期时间长度
     * @param timeUnit   过期时间单位
     * @return 是否创建成功
     */
    boolean initNewFilter(String key, Long expireDate, TimeUnit timeUnit, long expectedInsertions, double falseProbability);

    /**
     * 添加value到今天布隆过滤器
     * @param key  key
     * @param value  需要添加到过滤器的值
     * @return  是否添加成功
     */
    boolean add(final String key, final String value);

    /**
     * 添加value到今天布隆过滤器
     * @param key  key
     * @param list  需要添加到过滤器的值
     * @return  是否添加成功
     */
    boolean add(final String key, final List list);

    /**
     * 判断对应key是否有value值
     * @param key  key
     * @param value 对应key的value值
     * @return 应key是否有value值
     */
    boolean containsValue(final String key, final String value);

    /**
     * 查看是否存在key值
     * @param key  key
     * @return 是否有key值
     */
    boolean containKey(final String key);

}

实现类:

@Slf4j
@Service
public class RedissonBloomServiceImpl implements RedissonBloomFilterService {

    public static String prefix = "redission_bf_";


    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final int TIME_FORMAT_LENGTH = 8;

    @Resource
    private RedissonClient redissonClient;
    /**
     * 1、第一层的key为传入key值
     * 2、第二次key为  prefix + key+20200718
     */
    private Map> bloomFilterMap = new ConcurrentHashMap<>();

    @Override
    public synchronized boolean initNewFilter(String key, Long expireDate, TimeUnit timeUnit, long expectedInsertions, double falseProbability) {

        String timeFormatter = formatter.format(LocalDateTime.now());
        RBloomFilter bloomFilter = redissonClient.getBloomFilter(prefix + timeFormatter + key);
        //初始化布隆过滤器
        boolean isSuccess = bloomFilter.tryInit(expectedInsertions, falseProbability);

        if (isSuccess) {
            //设置过期时间
            bloomFilter.expire(expireDate, timeUnit);

            //设置过期监听器
            bloomFilter.addListener(new ExpiredObjectListener() {
                @Override
                public void onExpired(String key) {
                    log.info("onExpired callback running key is {}", key);
                    if (key.startsWith(prefix)) {
                        String firstKey = key.substring(prefix.length() + TIME_FORMAT_LENGTH);
                        ConcurrentHashMap map = bloomFilterMap.get(firstKey);
                        if (Objects.isNull(map)) {
                            log.warn("listener callback key is empty key is {}", key);
                            return;
                        }
                        map.remove(key);
                    }
                }
            });
            ConcurrentHashMap map = bloomFilterMap.computeIfAbsent(key, (k) -> {
                return new ConcurrentHashMap(4);
            });
            map.put(prefix + timeFormatter + key, bloomFilter);
            isSuccess = true;
        }else {
            log.error("initNewFilter fail key is {}", key);
        }
        return isSuccess;
    }

    @Override
    public boolean add(String key, String value) {
        String timeFormatter = formatter.format(LocalDateTime.now());
        ConcurrentHashMap map = bloomFilterMap.get(key);
        if (Objects.isNull(map)) {
            log.error("add name key one value is null, name is {},value is {}", key, value);
            return false;
        }
        RBloomFilter rBloomFilter = map.get(prefix + timeFormatter + key);
        if (Objects.isNull(rBloomFilter)) {
            log.error("add name key one value is null, name is {},redis key is {},value is {}", key, prefix + timeFormatter + key, value);
            return false;
        }
        return rBloomFilter.add(value);
    }

    @Override
    public boolean add(String key, List list) {
        String timeFormatter = formatter.format(LocalDateTime.now());
        ConcurrentHashMap map = bloomFilterMap.get(key);
        if (Objects.isNull(map)) {
            log.error("add name key list value is null, name is {}", key);
            return false;
        }
        RBloomFilter rBloomFilter = map.get(prefix + timeFormatter + key);
        if (Objects.isNull(rBloomFilter)) {
            log.error("add name key list value is null, name is {},redis key is {}", key,prefix + timeFormatter + key);
            return false;
        }
        list.forEach(value -> rBloomFilter.add(value));
        return true;
    }

    @Override
    public boolean containsValue(String key, String value) {
        ConcurrentHashMap map = bloomFilterMap.get(key);
        if (Objects.isNull(map)) {
            log.error("containsValue key is exist, key is {}", key);
            return false;
        }
        for (Map.Entry entry : map.entrySet()) {
            if (entry.getValue().contains(value)) {
                return true;
            }
        }
        return false;
    }


    @Override
    public boolean containKey(String key) {
        return bloomFilterMap.containsKey(key);
    }

}

测试类:(这里的测试,有关于已经存在值的判断)

 @Test
    public void testRedissonBloom() throws InterruptedException {
        //创建过滤器
        redissonBloomFilterService.initNewFilter("bloomkey1", 60L, SECONDS, 50, 0.1);
        redissonBloomFilterService.initNewFilter("bloomkey2", 60L, SECONDS, 50, 0.1);

        for (int i = 0; i < 50; i++) {
            redissonBloomFilterService.add("bloomkey1", "" + i);
            if (i > 30) {
                redissonBloomFilterService.add("bloomkey2", "" + i);
            }
        }
        int j1 = 0;
        int j2 = 0;
        for (int i = 0; i < 100; i++) {
            boolean exists = redissonBloomFilterService.containsValue("bloomkey1", "" + i);
            if (exists) {
                System.out.println("bloomkey1有误判" + (++j1) + "i是" + i);
            }
            boolean exists2 = redissonBloomFilterService.containsValue("bloomkey2", "" + i);
            if (exists2) {
                System.out.println("bloomkey2" +
                        "有误判" + (++j2) + "i是" + i);
            }
        }

        CountDownLatch beginCount = new CountDownLatch(1);
        beginCount.await();

    }

你可能感兴趣的:(redis)