前言
布隆过滤器是不支持重置的,如果我们对数据库进行了写操作(insert、update、delete),如何处理布隆过滤器中的数据?
insert:直接向布隆过滤器中添加数据。
update:id不变,更新的只是其他部分的数据。
delete:重置布隆过滤器
一、重置布隆过滤器的步骤
- 创建新的布隆过滤器
- 删除原来的布隆过滤器
- 将新的布隆过滤器重命名为原来的布隆过滤器
注意:2、3必须是原子性操作。
二、示例代码
@Slf4j
@Service
public class BloomFilterServiceImpl implements BloomFilterService {
@Autowired
private RedissonClient redissonClient;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private ProductBizService productBizService;
@Override
public void restBloomFilter() {
//创建新的布隆过滤器
RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(GmallConstant.CACHE_SKU_BLOOM_FILTER_NEW);
bloomFilter.tryInit(1000000, 0.0000001);
//调用productBizService存入skuid
List<Long> skuIds = productBizService.getSkuIds();
//存入布隆过滤器
skuIds.forEach(skuId -> {
bloomFilter.add(skuId);
});
bloomFilter.add(200L);
// //删除旧的布隆过滤器,并重命名新的布隆过滤器
String script = "redis.call('del' , KEYS[1])\n" +
"redis.call('del' , \"{\".. KEYS[1]..\"}:config\")\n" +
"redis.call('rename' , KEYS[2] , KEYS[1])\n" +
"redis.call('rename' , \"{\".. KEYS[2]..\"}:config\" , \"{\".. KEYS[1]..\"}:config\" )\n" +
"return 1 " ;
//执行lua脚本
Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(GmallConstant.CACHE_SKU_BLOOM_FILTER, GmallConstant.CACHE_SKU_BLOOM_FILTER_NEW));
if (result == 1){
log.info("布隆过滤器重置成功.......");
}
}
}
三、重置方式
手动重置请求接口
@RestController
@RequestMapping(value = "/restBloomFilter")
public class BloomFilterController {
@Autowired
private BloomFilterService bloomFilterService;
@GetMapping(value = "/rest")
public Result rest(){
bloomFilterService.restBloomFilter();
return Result.ok();
}
}
spring task定时任务
启动类上加注解
@EnableScheduling
@Service
@Slf4j
public class ResetBloomFilterTimeTask {
@Autowired
private BloomFilterService bloomFilterService;
@Scheduled(cron = "0/5 * * * * ?")
public void task() {
bloomFilterService.restBloomFilter();
log.info("定时任务重置布隆过滤器.............");
}
}
思考:如果服务是分布式的,每个服务都有一个定时任务,会造成对资源的浪费?
解决:1.分布式锁
2.分布式的任务调度框架,elastic job, xxl job