Redis4+布隆过滤器+lua实现方式、google布隆过滤器实现方式

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

二、布隆过滤器使用场景

 三、通过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

		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>21.0</version>
		</dependency>

 构建底库:

 private BloomFilter<Integer> bf;

    /***
     * PostConstruct 程序启动时候加载此方法
     */
    @PostConstruct
    public void initBloomFilter() {
        SysUserExample sysUserExample = new SysUserExample();
        List<SysUser> sysUserList = sysUserMapper.selectByExample(sysUserExample);
        if(CollectionUtils.isEmpty(sysUserList)){
            return;
        }
        //创建布隆过滤器(默认3%误差)
        bf = BloomFilter.create(Funnels.integerFunnel(),sysUserList.size());
        for (SysUser sysUser:sysUserList) {
            bf.put(sysUser.getId());
        }
    }

查询是否存在:


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

四、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

local bloomName = KEYS[1]
local value = KEYS[2]

-- bloomFilter
local result_1 = redis.call('BF.ADD', bloomName, value)
return result_1

bloomFilterExist.lua

local bloomName = KEYS[1]
local value = KEYS[2]

-- bloomFilter
local result_1 = redis.call('BF.EXISTS', bloomName, value)
return result_1

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

新增:

   private static final String bloomFilterName = "isVipBloom";   
    @Resource
    private RedisService redisService;

    @RequestMapping("/bloom/redisIdAdd")
    public boolean redisidAdd(int id){
        return redisService.bloomFilterAdd(bloomFilterName,id);
    }

    @Autowired
    private RedisTemplate redisTemplate;

    public Boolean bloomFilterAdd(String filterName,int value){
        DefaultRedisScript<Boolean> bloomAdd = new DefaultRedisScript<>();
        bloomAdd.setScriptSource(new ResourceScriptSource(new ClassPathResource("bloomFilterAdd.lua")));
        bloomAdd.setResultType(Boolean.class);
        List<Object> keyList= new ArrayList<>();
        keyList.add(filterName);
        keyList.add(value+"");
        Boolean result = (Boolean) redisTemplate.execute(bloomAdd,keyList);
        return result;
    }

查询是否存在:


    @Resource
    private RedisService redisService;
  
    @RequestMapping("/bloom/redisIdExists")
    public boolean redisidExists(int id){
        return redisService.bloomFilterExists(bloomFilterName,id);
    }

    @Autowired
    private RedisTemplate redisTemplate;
   public Boolean bloomFilterExists(String filterName,int value){
        DefaultRedisScript<Boolean> bloomExists= new DefaultRedisScript<>();
        bloomExists.setScriptSource(new ResourceScriptSource(new ClassPathResource("bloomFilterExist.lua")));
        bloomExists.setResultType(Boolean.class);
        List<Object> keyList= new ArrayList<>();
        keyList.add(filterName);
        keyList.add(value+"");
        Boolean result = (Boolean) redisTemplate.execute(bloomExists,keyList);
        return result;
    }

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

 

 

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值