当前位置:   article > 正文

Redis4+布隆过滤器+lua实现方式、google布隆过滤器实现方式_redis 布隆跟 谷歌布隆结果不同

redis 布隆跟 谷歌布隆结果不同

一、布隆过滤器是什么,一定要用吗?

二、布隆过滤器使用场景

 三、通过google布隆过滤器存储数据

四、google布隆过滤器的缺点分析

五、Redis布隆过滤器安装

六、 Redis布隆过滤器与springboot的整合 (集合lua脚本)


导读:本博文介绍了布隆过滤器的使用场景,以及google布隆过滤器和redis布隆过滤器分别的使用方法。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在 

一、布隆过滤器是什么,一定要用吗?

布隆过滤器是什么:

布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难

优点:

相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。布隆过滤器存储空间和插入/查询时间都是常数。另外,散列函数相互之间没有关系,方便由硬件并行实现。布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势

缺点:

但是布隆过滤器的缺点和优点一样明显。误算率是其中之一。随着存入的元素数量增加,误算率随之增加。但是如果元素数量太少,则使用散列表足矣

流量攻击:故意访问不存在的数据,导致程序不断访问DB数据库的数据(缓存穿透-解决方式将空值加到缓存中,防止大量攻击到db)

安全阻截:当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉(提前做ID数据判断是否是合格的)

思考:key:10000 10001 10002 10003 千万大集合,查找key是否在集合里面 

java常用数据结构,判断key是否在集合中:
set map key,value list 有序get[0]、get[1];
list.contain (key)遍历数据,进行equals()比较,性能低 
set.contain(key) hashcode比较,性能较高,
64位大概会占用1G
map.get(key) hashcode比较,性能还行,会出现hashcode冲突问题

上述常用做法,用小数据量还可以,大数据量不是占用内存过高,就是性能很低

二、布隆过滤器使用场景

使用场景:

网页爬虫对URL的去重,避免爬取相同的URL地址;

反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱(同理,垃圾短信);

缓存穿透,将已存在的缓存放到布隆中,当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉。

 三、通过google布隆过滤器存储数据

通过google布隆过滤器存储会员数据:

1、程序启动时将数据放入内存中
2、google自动创建布隆过滤器
3、用户ID进来之后判断是否是会员

pom.xml

  1. <dependency>
  2. <groupId>com.google.guava</groupId>
  3. <artifactId>guava</artifactId>
  4. <version>21.0</version>
  5. </dependency>

 构建底库:

  1. private BloomFilter<Integer> bf;
  2. /***
  3. * PostConstruct 程序启动时候加载此方法
  4. */
  5. @PostConstruct
  6. public void initBloomFilter() {
  7. SysUserExample sysUserExample = new SysUserExample();
  8. List<SysUser> sysUserList = sysUserMapper.selectByExample(sysUserExample);
  9. if(CollectionUtils.isEmpty(sysUserList)){
  10. return;
  11. }
  12. //创建布隆过滤器(默认3%误差)
  13. bf = BloomFilter.create(Funnels.integerFunnel(),sysUserList.size());
  14. for (SysUser sysUser:sysUserList) {
  15. bf.put(sysUser.getId());
  16. }
  17. }

查询是否存在:

  1. /***
  2. * 判断id可能存在于布隆过滤器里面
  3. * @param id
  4. * @return
  5. */
  6. public boolean userIdExists(int id){
  7. return bf.mightContain(id);
  8. }

四、google布隆过滤器的缺点分析

google缺点:

内存级别产物
重启即失效
本地内存无法用在分布式场景
不支持大数据量存储

这里引入redis的布隆过滤器

可扩展性Bloom过滤器,一旦Bloom过滤器达到容量,就会在其上创建一个新的过滤器
不存在重启即失效或者定时任务维护的成本

基于goole实现的布隆过滤器需要启动之后初始化布隆过滤器缺点:需要网络IO,性能比基于内存的过滤器低

当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在 

五、Redis布隆过滤器安装

Redis布隆过滤器安装过程 自己构建一个bitMap
git在centos7下面的安装:    

1、安装git,直接使用yum安装即可:

yum -y install git

2、创建git用户,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。

useradd -m -d /home/git -s /usr/bin/git-shell git

3、初始化git仓库

mkdir -p /data/git

cd /data/git

git init --bare project1.git

chown git.git project1.git -R

4、创建免密钥

cd /home/git

mkdir .ssh

chmod 700 .ssh

touch .ssh/authorized_keys

chmod 600 .ssh/authorized_keys

chown git.git .ssh -R

下载并编译模块:

 $ git clone git://github.com/RedisLabsModules/rebloom
 $ cd rebloom
 $ make    # 当前路径会生成一个rebloom.so文件

 将Rebloom加载到Redis中,在redis.conf里面添加

loadmodule /usr/local/rebloom/rebloom.so

 # 更改配置后重启Redis即可
上述的安装提到需要重启Redis,但是生产环境的Redis可不是你想重启就重启的。使用MODULE LOAD 不重启redis加载rebloom插件
MODULE LOAD /"rebloom.so的绝对路径"/redisbloom.so

命令:

添加元素:BF.ADD(添加单个)、BF.MADD(添加多个)、BF.INSERT(添加多个)

检查元素是否存在:BF.EXISTS(查询单个元素)、BF.MEXISTS(查询多个元素)
BF.ADD bloom redis         
BF.EXISTS bloom redis#判断是否存在
BF.EXISTS bloom nonxist 

六、 Redis布隆过滤器与springboot的整合 (集合lua脚本)

bloomFilterAdd.lua

  1. local bloomName = KEYS[1]
  2. local value = KEYS[2]
  3. -- bloomFilter
  4. local result_1 = redis.call('BF.ADD', bloomName, value)
  5. return result_1

bloomFilterExist.lua

  1. local bloomName = KEYS[1]
  2. local value = KEYS[2]
  3. -- bloomFilter
  4. local result_1 = redis.call('BF.EXISTS', bloomName, value)
  5. return result_1

本博文因需通过浏览器验证添加效果,所以将新增通过id增加的放到controller中,正式开发过程中可根据业务项目启动中查询数据加到redis中或者每天定时更新redis过滤器值。

新增:

  1. private static final String bloomFilterName = "isVipBloom";
  2. @Resource
  3. private RedisService redisService;
  4. @RequestMapping("/bloom/redisIdAdd")
  5. public boolean redisidAdd(int id){
  6. return redisService.bloomFilterAdd(bloomFilterName,id);
  7. }
  8. @Autowired
  9. private RedisTemplate redisTemplate;
  10. public Boolean bloomFilterAdd(String filterName,int value){
  11. DefaultRedisScript<Boolean> bloomAdd = new DefaultRedisScript<>();
  12. bloomAdd.setScriptSource(new ResourceScriptSource(new ClassPathResource("bloomFilterAdd.lua")));
  13. bloomAdd.setResultType(Boolean.class);
  14. List<Object> keyList= new ArrayList<>();
  15. keyList.add(filterName);
  16. keyList.add(value+"");
  17. Boolean result = (Boolean) redisTemplate.execute(bloomAdd,keyList);
  18. return result;
  19. }

查询是否存在:

  1. @Resource
  2. private RedisService redisService;
  3. @RequestMapping("/bloom/redisIdExists")
  4. public boolean redisidExists(int id){
  5. return redisService.bloomFilterExists(bloomFilterName,id);
  6. }
  7. @Autowired
  8. private RedisTemplate redisTemplate;
  9. public Boolean bloomFilterExists(String filterName,int value){
  10. DefaultRedisScript<Boolean> bloomExists= new DefaultRedisScript<>();
  11. bloomExists.setScriptSource(new ResourceScriptSource(new ClassPathResource("bloomFilterExist.lua")));
  12. bloomExists.setResultType(Boolean.class);
  13. List<Object> keyList= new ArrayList<>();
  14. keyList.add(filterName);
  15. keyList.add(value+"");
  16. Boolean result = (Boolean) redisTemplate.execute(bloomExists,keyList);
  17. return result;
  18. }

 效果验证:放入111 333 ,查询111存在  ,444不存在

 

 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号