布隆过滤器在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
由最后的结果可见布隆过滤器的基本使用暂没出现什么问题