布隆过滤器是一种数据结构,由一个很长的二进制位数组和一系列随机映射函数组成,用于判断某个key一定不存在或者可能存在于某个集合中,它在存储空间占用和查询效率上非常有优势,但是存在一定的误算率,数据越多误算率越高。

当使用布隆过滤初始化一个key时,先对key使用一系列的映射函数映射后得出它在二进制数组中的一系列位置,然后把这些位置上的值设置为1。当进行查找时,同样对key使用一系列的映射函数进行映射得出它在数组中的一系列位置,如果这些位置上存在为0的值说明key一定不在集合中,如果这些位置上的值都是1说明key可能存储于集合中,但是不一定存在于集合中,因为有可能别的key把这些位置上的值设置成了1。

常见的布隆过滤器有goole的布隆过滤器、Redis布隆过滤器,google布隆过滤器使用的是JVM内存。

google布隆过滤器

<!--google bloom filter--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>20.0</version></dependency>
package com.tech.tech.redis.filter.service;import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import com.tech.tech.redis.filter.entity.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;import javax.annotation.PostConstruct;
import java.util.List;/*** @author lw* @since 2021/12/20*/
@Slf4j
@Service
public class BloomFilterService {//google bloom filter 基于JVM内存的布隆过滤器private BloomFilter<Long> bloomFilter;@AutowiredISysUserService sysUserService;@PostConstructvoid  init(){List<SysUser> list = sysUserService.list();if(CollectionUtils.isEmpty(list)){return;}bloomFilter=BloomFilter.create(Funnels.longFunnel(),list.size());list.forEach(sysUser -> {bloomFilter.put(sysUser.getId());});log.info("init bloom filter OK");}public boolean userIdExists(Long id){return bloomFilter.mightContain(id);}
}
package com.tech.tech.redis.filter.controller;import com.tech.tech.redis.filter.service.BloomFilterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/*** <p>*  前端控制器* </p>** @author lw* @since 2021-12-20*/
@RestController
@RequestMapping("/filter/sysUser")
public class SysUserController {@AutowiredBloomFilterService bloomFilterService;/*** google bloom filter* @param id* @return*/@GetMapping("id")Boolean id(long id){return bloomFilterService.userIdExists(id);}
}

在程序启动时,在数据库中查询出用户列表,根据全部的用户ID,使用布隆过滤器进行数据初始化。当访问接口时,根据传入的用户ID,使用布隆过滤器进行判断是否为数据库中的用户ID,如果返回false,表示肯定不是真实的用户ID,可以进行业务拦截处理;如果返回true,表示很可能为真实的用户,可以进行查询数据库。通过布隆过滤器,过滤掉大部分伪造的非法请求,通过布隆过滤器校验通过的请求再访问数据库,做核实,防止伪造大量请求访问数据库。

Redis布隆过滤器

Redis布隆过滤器,在早期版本Redis需要用BitMap实现,新版本Redis可以通过加载相关插件提供布隆过滤器功能。

下载插件
git clone https://github.com/RedisBloom/RedisBloom.git

RedisBloom-2.2.zip

解压后进入解压包进行编译

make

修改Redis的配置加载插件redisbloom.so

loadmodule /path/to/redisbloom.so

重启Redis

#使用redis-cli客户端进行操作:#往过滤器添加一个key
BF.ADD bloom redis#判断过滤器是否存在key redis
BF.EXISTS bloom redis

springboot访问Redis布隆过滤器

bloomFilterAdd.lua 添加数据到布隆过滤器

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by lw.
--- DateTime: 2021/12/21 10:21
---
local bloomName = KEYS[1]
local value = KEYS[2]
local result_1 = redis.call('BF.ADD',bloomName,value)
return result_1

bloomFilterExist.lua 判断数据是否一定不存在或可能存在

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by lw.
--- DateTime: 2021/12/21 10:24
---
local bloomName = KEYS[1]
local value = KEYS[2]
local result_1 = redis.call('BF.EXISTS',bloomName,value)
return result_1

RedisTemplate配置,防止乱码

package com.tech.tech.redis.filter.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.*;import javax.annotation.Resource;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;@Configuration
@EnableCaching
public class RedisConfig {//    @Bean
//    public RedisTemplate<String,String> redisTemplate(RedisConnectionFactory factory){
//        RedisTemplate<String,String> redisTemplate = new RedisTemplate<>();
//        redisTemplate.setConnectionFactory(factory);
//        return redisTemplate;
//    }@Beanpublic RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){RedisTemplate<String, String> redisTemplate = new RedisTemplate<String,String>();redisTemplate.setConnectionFactory(factory);// 使用Jackson2JsonRedisSerialize 替换默认序列化/**Jackson序列化  json占用的内存最小 */Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);/**Jdk序列化   JdkSerializationRedisSerializer是最高效的*/
//      JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();/**String序列化*/StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();/**将key value 进行stringRedisSerializer序列化*/redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setValueSerializer(stringRedisSerializer);/**将HashKey HashValue 进行序列化*/redisTemplate.setHashKeySerializer(stringRedisSerializer);redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}@Beanpublic KeyGenerator genValueKeyGenerator() {return (o, method, objects) -> {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(o.getClass().getSimpleName());stringBuilder.append(".");stringBuilder.append(method.getName());stringBuilder.append("[");for (Object obj : objects) {stringBuilder.append(obj.toString());}stringBuilder.append("]");return stringBuilder.toString();};}@Beanpublic CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {return new RedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),this.getRedisCacheConfigurationWithTtl(600), // 默认策略,未配置的 key 会使用这个this.getRedisCacheConfigurationMap() // 指定 key 策略);}private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();redisCacheConfigurationMap.put("UserInfoList", this.getRedisCacheConfigurationWithTtl(100));redisCacheConfigurationMap.put("UserInfoListAnother", this.getRedisCacheConfigurationWithTtl(18000));return redisCacheConfigurationMap;}private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofSeconds(seconds));return redisCacheConfiguration;}}
package com.tech.tech.redis.filter.controller;import com.tech.tech.redis.filter.service.BloomFilterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.List;/*** <p>*  前端控制器* </p>** @author lw* @since 2021-12-20*/
@RestController
@RequestMapping("/filter/sysUser")
public class SysUserController {@AutowiredBloomFilterService bloomFilterService;@Autowiredprivate RedisTemplate redisTemplate;private static final String bloomFilterName="userIdBloomFilter";/*** google bloom filter* @param id* @return*/@GetMapping("id")Boolean id(long id){return bloomFilterService.userIdExists(id);}/*** redis布隆过滤器 添加数据到布隆过滤器* @param id* @return*/@GetMapping("redis/idAdd")Boolean redisIdAdd(int id){DefaultRedisScript<Boolean> script = new DefaultRedisScript<>();script.setScriptSource(new ResourceScriptSource(new ClassPathResource("bloomFilterAdd.lua")));script.setResultType(Boolean.class);List<Object> keyList = new ArrayList<>();keyList.add(bloomFilterName);keyList.add(String.valueOf(id));Boolean res = (Boolean) redisTemplate.execute(script, keyList);return res;}/*** redis 布隆过滤器 判断数据是否一定不存在或者可能存在* @param id* @return*/@GetMapping("redis/idExist")Boolean redisIdExist(int id){DefaultRedisScript<Boolean> script = new DefaultRedisScript<>();script.setScriptSource(new ResourceScriptSource(new ClassPathResource("bloomFilterExist.lua")));script.setResultType(Boolean.class);List<Object> keyList = new ArrayList<>();keyList.add(bloomFilterName);keyList.add(String.valueOf(id));Boolean res = (Boolean) redisTemplate.execute(script, keyList);return res;}}

BloomFilter布隆过滤器相关推荐

  1. 三十七 Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中...

    Python分布式爬虫打造搜索引擎Scrapy精讲-将bloomfilter(布隆过滤器)集成到scrapy-redis中,判断URL是否重复 布隆过滤器(Bloom Filter)详解 基本概念 如 ...

  2. 使用BloomFilter布隆过滤器解决缓存击穿、垃圾邮件识别、集合判重

    Bloom Filter是一个占用空间很小.效率很高的随机数据结构,它由一个bit数组和一组Hash算法构成.可用于判断一个元素是否在一个集合中,查询效率很高(1-N,最优能逼近于1). 在很多场景下 ...

  3. BloomFilter 布隆过滤器

    BloomFilter 定义: 空间效率高的概率型数据结构,用来检查一个元素是否在一个集合中 原理: 当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1.检索时 ...

  4. bloomfilter的java实现,BloomFilter(布隆过滤器)原理及实战详解

    什么是 BloomFilter(布隆过滤器) 布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数.主要用于判断一个元素是否在一 ...

  5. 判断数组中某个元素除自身外是否和其他数据不同_布隆过滤器,我也是个处理过 10 亿数据的人...

    ❝ 文章收录在 GitHub JavaKeeper ,N线互联网开发必备技能兵器谱 什么是 BloomFilter 布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的.它实际上是 ...

  6. 布隆过滤器速度_布隆过滤器,你也可以处理十几亿的大数据

    文章收录在 GitHub JavaKeeper ,N线互联网开发必备技能兵器谱 什么是 BloomFilter 布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的.它实际上是一个 ...

  7. 5 Redis缓存穿透、击穿、雪崩、分布式锁、布隆过滤器

    1 Redis 应用问题解决 1.1 缓存穿透 1.1.1 问题描述 key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源(数据库),从而可能压垮数据源.比 ...

  8. Redis 高级主题之布隆过滤器(BloomFilter)

    最近计划准备整理几篇关于Reids高级主题的博文,本文整理的是关于布隆过滤器在Redis中如何应用,先来一张思维导图浏览全文. 1. 认识BloomFilter 1.1 原理 布隆过滤器,英文叫Blo ...

  9. 三种去重方式——HashSet、Redis去重、布隆过滤器(BloomFilter)

    三种去重方式 去重就有三种实现方式,那有什么不同呢? HashSet 使用java中的HashSet不能重复的特点去重.优点是容易理解.使用方便. 缺点:占用内存大,性能较低. Redis去重 使用R ...

最新文章

  1. mysql分类和事务回滚
  2. js----map和对象的区别
  3. 深度对比学习Vue和React两大框架
  4. linux C 基于链表链的定时器
  5. hadoop0.20.0第一个例子
  6. RabbitMQ 关键词解释
  7. C# 异常类型及对应异常类
  8. java 内存管理 知乎_[知乎]Java 语言的 GC 为什么不实时释放内存?
  9. Websense:别让移动设备触痛企业的安全神经
  10. [20150228]Delayed Block Cleanout 2.txt
  11. ROS教程(一):Ubuntu ROS安装详细教程(全过程)+测试程序
  12. 电脑网线,电脑网线主要分类
  13. Greenplum 安装部署 单机版安装(Linux)
  14. 判断矩形是否在矩形中
  15. 笔记本电脑无法连接网络并在网络状态中显示ipv4和ipv6无网络访问权限
  16. Bable的简单使用
  17. 如何计算机闲置虚拟机算法_利用闲置计算机的最佳方法
  18. Panda3D 是一个用于 Python 和 C++ 程序的 3D 渲染和游戏开发框架。
  19. 嵌入式设备和固件中的自动漏洞检测(一):概览
  20. 致:同年代的童真童鞋们

热门文章

  1. echo 3 drop_如何通过Drop In将Amazon Echo用作对讲机
  2. CentOS安装Redis教程
  3. 【LeetCode】详解环形链表141. Linked List Cycle Given a linked list, determine if it has a cycle in it. To
  4. javascript 的七七八八
  5. Oracle数据库实验4 Oracle数据库安全管理
  6. go-micro框架
  7. UE4官网教程 风格化效果
  8. UltraEdit脱机激活工具
  9. Ubuntu16.04 E: 无法定位软件包(绝不是更换镜像源这种千篇一律无效的解决方案) (已解决)
  10. 【行业标准】YBT091-2019-锻轧钢球