数据库
布隆过滤器
  • By刘立博
  • 2020-03-07 21:03:49
  • 764人已阅读

布隆过滤器与HyperLogLog类似都是与set类似的数据结构,但HyperLogLog侧重于统计不重复元素的数量,而布隆过滤器侧重于判断一个元素是否被添加过。Redis官方提供的布隆过滤器直到Redis4.0提供了插件功能后才正式登场,为Redistribution提供了强大的布隆去重功能。

 

布隆过滤器算法原理

见:《布隆过滤器算法原理》

 

布隆过滤器插件安装

见:《CentOS7部署Redis 5.0.7》

 

基本使用

 

添加元素

向bloomTest添加user1元素

 

192.168.3.9:6379> bf.add bloomTest user1
(integer) 1

 

判断是否存在

判断bloomTest是否存在user2元素

 

192.168.3.9:6379>  bf.exists counter6 user2
(integer) 0

 

Spring Data Redis使用布隆过滤器

向过滤器添加100W个元素(user0-user1000000),并判断元素user10000和user-1是否存在

 

@SpringBootTest
public class BloomRedis {

    @Autowired
    RedisTemplate<String,String> redisTemplate;

    @Test
    public void bloom()
    {
        for (int i = 0; i < 1000000; i++) {
            add("user"+i);
        }

        System.out.println(exists("user10000"));
        System.out.println(exists("user-1"));
    }

    /**
     * 判断元素是否存在
     */
    private Boolean exists(String userName)
    {
        String bfExistsScriptString = "return redis.call('bf.exists',KEYS[1],ARGV[1])";
        DefaultRedisScript<Boolean> bfExistsScript = new DefaultRedisScript<>(bfExistsScriptString, Boolean.class);
        return redisTemplate.execute(bfExistsScript, Collections.singletonList("bloom"), userName);
    }

    /**
     * 添加元素
     */
    private Boolean add(String userName)
    {
        String bfAddScriptString = "return redis.call('bf.add',KEYS[1],ARGV[1])";
        DefaultRedisScript<Boolean> bfAddScript= new DefaultRedisScript<>(bfAddScriptString, Boolean.class);
        return redisTemplate.execute(bfAddScript, Collections.singletonList("bloom"), userName);
    }
    
}

输出:true,false

 

布隆过滤器能解决哪些业务问题?

 

缓存穿透问题

如果我们对文章ID设置了缓存,正常情况下大多数文章都被缓存在redis中,但是如果有人刻意生成了大量不存在的ID进行查询,就会极大的增加数据库访问压力,甚至造成服务器宕机

 

缓存主键

可以将文章ID作为元素添加进布隆过滤器,当缓存被穿透时,可以判断此ID是否存在,如果不存在就无需查询数据库

 

缓存空值

如果某ID没有对应的记录,则添加至布隆过滤器。在一定时间避免对空结果反复查询

 

判断用户有没有访问过某资源

我们可以使用布隆过滤器记录用户有没有访问过某篇文章,这样不但比在数据表中记录更加高效,还能节省大量的磁盘空间