背景

在使⽤word⽂档时,word如何判断某个单词是否拼写正确?

⽹络爬⾍程序,怎么让它不去爬相同的url⻚⾯?

垃圾邮件(短信)过滤算法如何设计?

公安办案时,如何判断某嫌疑⼈是否在⽹逃名单中?

缓存穿透问题如何解决?

先来看一个场景,假如我们的数据库使用的是 mysql,缓存使用 redis。

server

redis

mysql

数据读取步骤是这样的:

先访问 redis ,如果数据存在直接返回;如果不存在则进行步骤 2;

访问 mysql ,如果数据不存在,直接返回;如果存在则进行步骤 3;

将 mysql 中存在的 key 写回 redis;

出现的问题: 如果 redis 和 mysql 中都没有相应的数据,此时又有大量的该数据的请求(伪造数据攻击),最终的压力还是会全部涌向 mysql。这就是所谓的 缓存穿透。

解决方案:

在 redis 端设置 键值对,以避免访问 mysql。当然缺点是如果 过多时会占用过多的内存。我们可以给 key 设置过期时间,比如 exoire key 600ms, 停止攻击后最终由 redis 自动清除这些无用的 key ;

在 server 端设置一个布隆过滤器,将 mysql 中包含的 key 放入布隆过滤器中;布隆过滤器能过滤一定不存在的数据。

布隆过滤器

假设我么你现在提出一个需求:从海量数据中查询某字符串是否存在。

在 c++ 中我们首先想到的应该是使用 STL 中的 set 或者 map。

set 和 map

c++ 标准库(STL)中的 set 和 map 结构都是采⽤红⿊树实现的,它增删改查的时间复杂度是:

o

(

l

o

g

2

n

)

o(log_{2}n)o(log2​n)

对于严格平衡⼆叉搜索树(AVL),100w 条数据组成的红⿊树,只需要⽐较20次就能找到该值;对于10亿条数据只需要⽐较30次就能找到该数据;也就是查找次数跟树的⾼度是⼀致的;

对于红⿊树来说平衡的是⿊节点⾼度,所以研究⽐较次数需要考虑树的⾼度差,最好情况某条树链路全是⿊节点,假设此时⾼度为 h1,最差情况某条树链路全是⿊红节点间隔,那么此时树⾼度为 2*h1;

在红⿊树中每⼀个节点都存储 key 和 val 字段,key 是⽤来做⽐较的字段;红⿊树并没有要求 key 字段唯⼀,在 set 和 map 实现过程中限制了 key 字段唯⼀。

另外 set 和 map 的关键区别是 set 不存储 val 字段;

优点:存储效率⾼,访问速度⾼效;

缺点:对于数据量⼤且查询字符串⽐较⻓且查询字符串相似时将会是噩梦;

unordered_map

c++ 标准库(STL)中的 unordered_map 是采⽤ hashtable 实现的;

构成:数组 + hash 函数;

它是将字符串通过 hash 函数⽣成⼀个整数再映射到数组当中;它增删改查的时间复杂度是 o(1);

hash 函数的作⽤:避免插⼊的时候字符串的⽐较;hash函数计算出来的值通过对数组⻓度的取模能随机分布在数组当中;

hash 函数⼀般返回的是 64 位整数,将多个⼤数映射到⼀个⼩数组中,必然会产⽣冲突;

如何选取 hash 函数?

选取标准:

选取计算速度快;

哈希相似字符串能保持强随机分布性(防碰撞);

murmurhash1,murmurhash2,murmurhash3,siphash( redis6.0 当中使⽤,rust 等⼤多数语⾔选⽤的 hash 算法来实现 hashmap),cityhash 都具备强随机分布性;测试地址如下:https://github.com/aappleby/smhasher

负载因⼦:数组存储元素的个数/数组⻓度;负载因⼦越⼩,冲突越⼩;负载因⼦越⼤,冲突越⼤;

hash冲突解决⽅案

链表法

引⼊链表来处理哈希冲突;也就是将冲突元素⽤链表链接起来;这也是常⽤的处理冲突的⽅式;但是可能出现⼀种极端情况,冲突元素⽐较多,该冲突链表过⻓,这个时候可以将这个链表转换为红⿊树;由原来链表时间复杂度 o(n) 转换为红⿊树时间复杂度 ;那么判断该链表过⻓的依据是多少?可以采⽤超过256(经验值)个节点的时候将链表结构转换为红⿊树结构;

开放寻址法

将所有的元素都存放在哈希表的数组中,不使⽤额外的数据结构;⼀般使⽤线性探查的思路解决;

当插⼊新元素的时,使⽤哈希函数在哈希表中定位元素位置;

检查数组中该槽位索引是否存在元素。如果该槽位为空,则插⼊,否则进行第 3 步;

在第 2 步检测的槽位索引上加⼀定步⻓接着检查第 2 步;

加⼀定步⻓分为以下⼏种:

i+1,i+2,i+3,i+4 ... i+n

i- ,i+ ,i- ,1+ ...

这两种都会导致同类 hash 聚集;也就是近似值它的 hash 值也近似,那么它的数组槽位也靠近,形成 hash 聚集;第⼀种同类聚集冲突在前,第⼆种只是将聚集冲突延后;

另外还可以使⽤双重哈希来解决上⾯出现 hash 聚集现象。

在 .net HashTable 类的 hash 函数 Hk 定义如下:

Hk(key) = [GetHash(key) + k * (1 + (((GetHash(key) >> 5) + 1) %(hashsize – 1)))] % hashsize

在此 (1 + (((GetHash(key) >> 5) + 1) % (hashsize – 1))) 与 hashsize互为素数(两数互为素数表示两者没有共同的质因⼦);执⾏了 hashsize 次探查后,哈希表中的每⼀个位置都有且只有⼀次被访问到,也就是说,对于给定的 key,对哈希表中的同⼀位置不会同时使⽤ Hi 和 Hj。

具体原理:https://www.cnblogs.com/organic/p/6283476.html

同样的 hashtable 中节点存储了 key 和 val,hashtable 并没有要求 key 的⼤⼩顺序,我们同样可以修改代码让插⼊存在的数据变成修改操作;

优点:访问速度更快;不需要进⾏字符串⽐较;

缺点:需要引⼊策略避免冲突,存储效率不⾼;空间换时间;

总结

红⿊树和 hashtable 都不能解决海量数据问题,它们都需要存储具体字符串,如果数据量⼤,提供不了⼏百 G 的内存;所以需要尝试探寻不存储 key 的⽅案,并且拥有 hashtable 的优点(不需要⽐较字符串);

布隆过滤器

布隆过滤器是⼀种概率型数据结构,它的特点是⾼效的插⼊和查询,能明确告知某个字符串⼀定不存在或者可能存在;相⽐传统的查询结构(例如:hash,set,map等数据结构)更加⾼效,占⽤空间更⼩;但是其缺点是它返回的结果是概率性的,也就是说结果存在误差的,虽然这个误差是可控的;同时它不⽀持删除操作;

组成:位图(bit 数组)+ n 个 hash 函数

原理:当⼀个元素加⼊位图时,通过 k 个 hash 函数将这个元素映射到位图的 k 个点,并把它们置为 1;当检索时,再通过 k 个 hash 函数运算检测位图的 k 个点是否都为 1;如果有不为 1 的点,那么认为不存在;如果全部为1,则可能存在(存在误差);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ahhhbjn3-1610794049644)(原理.png)]

在位图中每个槽位只有两种状态(0 或者 1),⼀个槽位被设置为 1 状态,但不明确它被设置了多少次;也就是不知道被多少个 str1 哈希映射以及是被哪个 hash 函数映射过来的;所以不⽀持删除操作;

在实际应⽤过程中,布隆过滤器该如何使⽤?要选择多少个 hash 函数,要分配多少空间的位图,存储多少元素?另外如何控制假阳率(布隆过滤器能明确⼀定不存在,不能明确⼀定存在,那么存在的判断是有误差的,假阳率就是错误判断存在的概率)?

n -- 布隆过滤器中元素的个数,如上图 只有str1和str2 两个元素 那么 n=2

p -- 假阳率,在0-1之间 0.000000

m -- 位图所占空间

k -- hash函数的个数

公式如下:

n = ceil(m / (-k / log(1 - exp(log(p) / k))))

p = pow(1 - exp(-k / (m / n)), k)

m = ceil((n * log(p)) / log(1 / pow(2, log(2))));

k = round((m / n) * log(2));

假定我们选取这四个值为:

n = 4000

p = 0.000000001

m = 172532

k = 30

四个值的关系:

在实际应⽤中,我们确定 n 和 p,通过上⾯的计算算出 m 和 k;也可以在⽹站上选取合适的值:https://hur.st/bloomfilter

已知 k,如何选择 k 个 hash 函数?

// 采⽤⼀个hash函数,给hash传不同的种⼦偏移值

// #define MIX_UINT64(v) ((uint32_t)((v>>32)^(v)))

uint64_t hash1 = MurmurHash2_x64(key, len, Seed);

uint64_t hash2 = MurmurHash2_x64(key, len, MIX_UINT64(hash1));

for (i = 0; i < k; i++) // k 是hash函数的个数

{

Pos[i] = (hash1 + i*hash2) % m; // m 是位图的⼤⼩

}

// 通过这种⽅式来模拟 k 个hash函数 跟我们前⾯开放寻址法 双重hash是⼀样的思路

mysql开启布隆过滤器_海量数据去重之布隆过滤器相关推荐

  1. mysql开启邮件服务_邮件服务

    一.基础配置 1.需要两台环境纯净的虚拟机 2.更改主机名分别为   westos-mail.westos.com   和  qq-mail.qq.com 3.配置两台虚拟机的yum源,使两台虚拟机可 ...

  2. mysql 开启守护进程_[求助]Linux上MySQL Server 5.6 安装后无法启动守护进程

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 1 所谓的初始化数据库脚本运行错误 /usr/local/mysql/scripts/mysql_install_db --basedir=/usr/lo ...

  3. mysql开启邮件服务_邮件服务之实现基于虚拟用户的虚拟域邮件系统

    postfix+dovecot+SASL+mysql+apache+extmail+extman实现基于虚拟用户的虚拟域邮件系统 声明:省略了前面的基础配置包括安装MYSQL,postfix等,这里用 ...

  4. COSMIC的后端学习之路——1.3 海量数据去重的Hash与BloomFilter(布隆过滤器),bitmap(位图)

    1.3 海量数据去重的Hash与BloomFilter,bitmap 知识树 1.海量数据查找的应用场景 2.平衡二叉树 3.哪些算法涉及二分查找 4.散列表 (1)hash冲突 (2)负载因子 (3 ...

  5. 海量数据去重,hash、布隆过滤器以及hyperloglog丨c/c++linux服务器开发丨后端开发丨Linux后台开发丨底层原理

    海量数据去重,hash.布隆过滤器以及hyperloglog 视频讲解如下,点击观看: 海量数据去重,hash.布隆过滤器以及hyperloglog丨c/c++linux服务器开发丨后端开发丨Linu ...

  6. 海量数据去重hash与布隆过滤器

    海量数据去重hash与布隆过滤器 背景 缓存穿透 需求 set和map unordered_map 总结 布隆过滤器 代码 背景 在使⽤word⽂档时,word如何判断某个单词是 否拼写正确? ⽹络爬 ...

  7. Flink 结合 布隆过滤器(BloomFilter) 实现去重

    本文开头附:Flink 学习路线系列 ^ _ ^ 1.实时系统去重方案 使用Redis,将实时系统每条数据都去和 Redis 进行判断: 使用 HashSet,因为 HashSet 本身就是无序不重复 ...

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

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

  9. filter过滤器_不了解布隆过滤器?一文给你整的明明白白!

    海量数据处理以及缓存穿透这两个场景让我认识了 布隆过滤器 ,我查阅了一些资料来了解它,但是很多现成资料并不满足我的需求,所以就决定自己总结一篇关于布隆过滤器的文章.希望通过这篇文章让更多人了解布隆过滤 ...

最新文章

  1. source insight快捷键及使用技巧
  2. Allegro跨分割检查
  3. 代码内容变成图片_网站只剩25行代码,真有程序员“删库跑路”?
  4. linux 测试环境启用jar_Linux下搭建测试环境
  5. chardet java_java实现文件编码监测
  6. Python是什么?Python能干什么?一篇文章让你对Python了如指掌!!
  7. 水文特点是什么意思_水文监测仪器设备简介
  8. 在线颜色拾取器 - 资源篇
  9. YIi2 對接 支付寶Alipay支付接口
  10. 放弃百万年薪,独自创业,我做错了吗?
  11. IE6 Hotfix MS-042将导致其Crash!
  12. python打印右对齐_python右对齐的实例方法
  13. Qsys中的EPCS使用技巧
  14. mig是指_mignt是什么意思
  15. python学习之面对对象程序设计作业
  16. Go语言优秀的Revel开源框架推荐
  17. 如何自给自足获取磁力种子
  18. day01 Python基础
  19. 多个PDF文件怎么合并?PDF合并的方法教程
  20. FPGA学习---3.IP核使用,Counter IP核

热门文章

  1. 前端学习(2832):小程序事件绑定2
  2. 工作239:内容过长省略号失败 直接改的样式表
  3. 工作234:按钮禁用
  4. 前端学习(2662):vue3.0的todolist制作演示
  5. 工作108:精准的v-for和if
  6. 前端学习(1258):then参数中的函数返回值
  7. 前端学习(593):使用devtools作为代码编辑器
  8. css3修改input[type=radio]样式
  9. python一次性输入3个数_python实现输入数字的连续加减方法
  10. 怎么把整个网站的代码中的一个词去掉_【杭州南牛网络】网站优化的最新优化方法...