高并发11-布隆过滤器
前言
- 黑客流量攻击:故意访问不存在的数据,导致程序不断访问DB数据库的数据(缓存击穿)
- 黑客安全阻截:当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉
- 思考:如果让你实现这个功能你会怎么做? key:10000 10001 10002 10003 大集合,key是否在集合里面
- 温故而知新:分析java常用数据结构复习 set map key,value list 有序get[0]、get[1];
- list.contain (key)遍历数据,进行equals()比较,性能小
- set.contain(key) hashcode比较,性能较高,64位 1G
- map.get(key) hashcode比较,性能还行
- 概念:
- **布隆过滤器**(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的[二进制](https://zh.wikipedia.org/wiki/%E4%BA%8C%E8%BF%9B%E5%88%B6)向量和一系列随机[映射函数](https://zh.wikipedia.org/wiki/%E6%98%A0%E5%B0%84)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
- 优点:
- 相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。布隆过滤器存储空间和插入/查询时间都是常数({\displaystyle O(k)})。另外,散列函数相互之间没有关系,方便由硬件并行实现。布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势
- 缺点
- 但是布隆过滤器的缺点和优点一样明显。误算率是其中之一。随着存入的元素数量增加,误算率随之增加。但是如果元素数量太少,则使用散列表足矣
- 布隆过滤器的其他使用场景
**网页爬虫对URL的去重,避免爬取相同的URL地址;**
**反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱(同理,垃圾短信);**
**缓存击穿,将已存在的缓存放到布隆中,当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉。**
- 布隆过滤器实现原理图解

谷歌布隆过滤器实现会员转盘抽奖
- 需求分析步骤
* 互联网功能需求分析
* 这是一个抽奖程序,只针对会员用户有效
* 抽离出功能所有api
* 制定存储方案
* 性能优化方案分析

- 成型互联网产品用户量上千万,日常百万,怎么做到高性能非会员过滤
- 这是一个布隆过滤器的经典使用场景
- 通过google布隆过滤器存储会员数据实战
引入jar包
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>21.0</version> </dependency>
* 程序启动时将数据放入内存中
package com.concurrent.service; import com.concurrent.domain.SysUser; import com.concurrent.domain.SysUserExample; import com.concurrent.mapper.SysUserMapper; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.List; @Service public class BloomFilterService { @Resource private SysUserMapper sysUserMapper; 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自动创建布隆过滤器
* 用户ID进来之后判断是否是会员
package com.concurrent.controller; import com.concurrent.service.BloomFilterService; import com.concurrent.util.RedisService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController public class BloomFilterController { @Resource private BloomFilterService bloomFilterService; @Resource private RedisService redisService; @RequestMapping("/bloom/idExists") public boolean ifExists(int id){ return bloomFilterService.userIdExists(id); } }
- 数据库
CREATE TABLE `sys_user` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `user_name` varchar(11) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '用户名', `image` varchar(11) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '用户头像', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
goole布隆过滤器与Redis布隆过滤器
- google布隆过滤器的缺陷与思考
- 基于内存布隆过滤器有什么特点
- 内存级别产物
- 重启即失效
- 本地内存无法用在分布式场景
- 不支持大数据量存储
- 需求分析步骤
- 互联网功能需求分析
- 这是一个抽奖程序,只针对会员用户有效
- 抽离出功能所有api
- 制定存储方案
- 性能优化方案分析
- Redis布隆过滤器
* 可扩展性Bloom过滤器
* 一旦Bloom过滤器达到容量,就会在其上创建一个新的过滤器
* 不存在重启即失效或者定时任务维护的成本
* 基于goole实现的布隆过滤器需要启动之后初始化布隆过滤器
* 缺点:
* 需要网络IO,性能比基于内存的过滤器低
- 选择:
优先基于数据量进行考虑


浙公网安备 33010602011771号