- By刘立博
- 2020-03-07 21:03:49
- 764人已阅读
布隆过滤器与HyperLogLog类似都是与set类似的数据结构,但HyperLogLog侧重于统计不重复元素的数量,而布隆过滤器侧重于判断一个元素是否被添加过。Redis官方提供的布隆过滤器直到Redis4.0提供了插件功能后才正式登场,为Redistribution提供了强大的布隆去重功能。
布隆过滤器算法原理
布隆过滤器插件安装
基本使用
添加元素
向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没有对应的记录,则添加至布隆过滤器。在一定时间避免对空结果反复查询
判断用户有没有访问过某资源
我们可以使用布隆过滤器记录用户有没有访问过某篇文章,这样不但比在数据表中记录更加高效,还能节省大量的磁盘空间