亿级数据判断 bitmap-布隆过滤器
缓存穿透
假设我们使用redis缓存了商品信息,当我们请求进来时,首先经过的是redis,当redis不存在时,才会去查找mysql.然后将mysql的数据缓存到redis.
整个流程看上去是没有任何问题的,但当前端在同一时间发生了大量请求,同时去请求一个redis,数据库都不存在的商品id,会发生什么情况呢?
1: 先去访问redis,发现redis不存在缓存
2: 查询mysql.mysql不存在缓存,则无法进行redis缓存
3: 下一次请求继续循环.....
这个情况,由于redis无法缓存数据,导致每次请求都会直接到数据库,数据库压力剧增,导致宕机.
短网址判断
短网址服务大家都应该比较熟悉,
如果有个短网址服务,现在存储了1亿条短网址.
当你访问 1.cn/arhwqwqwe 这串字符时
同缓存穿透,短网址服务器会先去请求redis缓存,当redis缓存不存在时,请求mysql数据库.....
bitmap
布隆过滤器基于 大数据存储处理-bitmap的艺术
通过 目标数据的 标识hash为位的下标,目标数据存在则为1,不存在则为0
例如:
1,3,5,6,7 5个值,在bitmap中表示为:
二进制表示为:(从右往左)
0b11101010
如果我们需要判断id 2是否存在,只需要根据2所在的位置去判断即可:
$bitmap = 0b11101010;
$goodsId = 3;
$bitToNum = 1 << $goodsId;//算出这个数字的二进制位数
echo "goodsId 2的二进制:" . decbin($bitToNum), PHP_EOL;
$tempNum = $bitmap & $bitToNum;
echo "位运算结果:" . decbin($tempNum), PHP_EOL;
if ($tempNum != $bitToNum) {
echo "商品id:{$goodsId}不存在n";
}else{
echo "商品id:{$goodsId}存在n";
}
看到这里,是不是发现有点熟悉?没错,这个是我从大数据存储处理-bitmap的艺术 复制过来的代码,可以看出,如果是商品id这种id类型的,可以直接使用bitmap判断存在或者不存在,那布隆过滤器呢?
布隆过滤器
布隆过滤器是一个非常长的bitmap组成,通过随机散列函数,将数据随机映射到bitmap的位置中.
它的存储步骤为:
1: 创建一个足够大的bitmap,例如10亿
2: 将需要判断的key,通过hash 映射函数,例如(md5(key)%10亿),将其指定到bitmap的一个位置中
3: 将bitmap该位置置为1
它的判断步骤为:
1: 将需要判断的key,通过hash映射函数,例如(md5(key)%10亿),获取其指定位置.
2: 找到bitmap的该位置,如果为0,则代码该key一定不存在,如果为1,则可能存在
php实现代码:(本文的hash函数用的是php自带的crc32算法)
<?php
/**
* Created by PhpStorm.
* User: xdd
* Date: 2020/9/21
* Time: 10:23
*/
/**
* Created by PhpStorm.
* User: apple
* Date: 2020-04-30
* Time: 14:25
*/
class BloomFilter
{
//由于php的int为64位,如果要存储10亿,或者更大的数据,需要通过多个int数组实现
protected $bitmap = [];
//一个int,只能表示0-64的数字
//10亿的数字
protected $maxNum = 1 << 30;
function add($key)
{
$hash = $this->hash($key);
$bitmapKey = $this->getBitmapKey($hash);
if (isset($this->bitmap[$bitmapKey])) {
//如果已经添加了这个数组,则直接与运算将数据加上
$this->bitmap[$bitmapKey] = $this->bitmap[$bitmapKey] | (1 << ($hash % 64));
} else {
$this->bitmap[$bitmapKey] = 1 << ($hash % 64);
}
return $hash;
}
function get($key)
{
$hash = $this->hash($key);
$bitmapKey = $this->getBitmapKey($hash);
if (isset($this->bitmap[$bitmapKey])) {
$bitToNum = 1 << ($hash % 64);//算出这个数字的二进制位数
$tempNum = $this->bitmap[$bitmapKey] & $bitToNum;
if ($tempNum != $bitToNum) {
return false;
}
return true;
} else {
return false;
}
}
function hash($key)
{
$hash = crc32($key);
//time33返回的数据是0-2^31,目前我们的设想是只存储2^30,所以取余
$hash = $hash % $this->maxNum;
return $hash;
}
function getBitmapKey($data)
{
$key = intval($data / 64);
return $key;
}
}
$bloomFilter = new BloomFilter();
$str = "测试1234";
$hash = $bloomFilter->add($str);
var_dump($bloomFilter->get($str));
var_dump($bloomFilter->get('213312'));
注意事项
需要注意的是,
布隆过滤器 重复率依靠的是hash算法,所以越完善的hash算法,分配的数据越均匀,冲突率越低
同时,布隆过滤器只能验证一个值 一定不存在或可能存在
应用场景
1:url短网址生成判断,如果不存在,则代表该url一定没有生成过,可以直接返回404
2:恶意url判断,如果存在,则表示该url可能有问题,可以进一步过滤判断
3:解决上面说的缓存穿透问题
本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn
- 上一篇: php hash算法类
- 下一篇: mysql实现定时全量备份
- 3101: N皇后
- 算法模板——线性欧拉函数
- jdbc基础 (一) MySQL的简单使用
- 小白博客 爆破内网mysql数据库root密码脚本代码
- 2818: Gcd
- 1688: [Usaco2005 Open]Disease Manangement 疾病管理
- 通过MySQL自动同步刷新Redis
- 13.MySQL(一) 数据库简介mysql安装数据库操作Mysql数据类型存储引擎
- 3314: [Usaco2013 Nov]Crowded Cows
- BZOJ4766: 文艺计算姬
- 14.MySQL(二) 数据之表操作表内容操作Mysql 连接事务外键
- 3450: Tyvj1952 Easy
- SP104 HIGH - Highways
- 1664: [Usaco2006 Open]County Fair Events 参加节日庆祝
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Sublime Text3 通过Package Control安装插件时找不到可用安装包的解决方法
- SwiftUI:手动发布 ObservableObject 更改
- 卧槽,又一款 Markdown 组合神器!!!
- SQL-查询各工程项目使用所提供零件最多的供应商
- 浙大版《C语言程序设计(第3版)》题目集 习题8-3 数组循环右移
- SwiftUI:控制图像插值
- SQL-查询比p6零件供应数量都高的零件
- 浙大版《C语言程序设计(第3版)》题目集 习题8-5 使用函数实现字符串部分复制
- 最小生成树-Magicpig密室出逃(Kruskal+并查集)
- 浙大版《C语言程序设计(第3版)》题目集 习题8-6 删除字符
- SQL-显示供应商供应零件的汇总列表(with rollup+coalesce)
- 浙大版《C语言程序设计(第3版)》题目集 习题8-8 判断回文字符串
- 双向广搜-HDU1401 Solitaire
- TCP三次握手和四次挥手以及11种状态
- 浙大版《C语言程序设计(第3版)》题目集 题8-9 分类统计各类字符个数