刷抖音的时候是否曾想过,我们刷过的视频很难在重复刷到那么它到底是如何实现的呢?

如果说我们每刷一个视频并且把视频id和用户的id组合成一条数据保存到数据库中每次推荐视频的时候都去数据检测是否已经刷过了,嗯,这样可以实现这个功能,但是存在多个问题,频繁操作数据表对数据库造成很大的负担,每次推荐视频时都得保存数据,人流量一多,数据库很快就扛不住。

那么我们可否使用缓存redis中的set来实现呢?当然是可以的,redis4.0版本给我们提供了更加快捷更加节省空间的数据结构--布隆过滤器(Bloom Filter)

布隆过滤器的简介

布隆过滤器(BloomFilter)是一个很长的二进制向量和一系列随机映射函数,我们也可以简单的理解为它是一个不怎么精确的set结构。本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。相比于传统的List、Set、Map等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,但是我们不必过于担心它不够精确,只要参数设置合理,它的精度可以控制到足够的精确。

适用场景:

  • 大数据是否存在的问题,比如上述的刷抖音去重问题

  • 解决缓存击穿问题,如果数据请求一直是一个不存在的内容,那么它会越过缓存直接请求数据库,造成缓存击穿,布隆过滤器也可以解决此类问题

  • 解决爬虫爬到重复url内容等等

布隆过滤器基本使用

布隆过滤器有二个基本指令,bf.add添加元素,bf.exists查询元素是否存在,它的用法和set集合的sadd和sismember差不多。注意bf.add只能一次添加一个元素,如果想要一次添加多个,就需要用到bf.madd指令。同样如果需要一次查询多个元素是否存在,就需要用到bf.mexists指令。

> bf.add user user1(integer) 1> bf.add user user2(integer) 1> bf.add user user3(integer) 1> bf.exists user user1(integer) 1> bf.exists user user4(integer) 0> bf.madd user user4 user5 user61) (integer) 12) (integer) 13) (integer) 1> bf.mexists user user4 user5 user6 user71) (integer) 12) (integer) 13) (integer) 14) (integer) 0

上面使用的布隆过过滤器只是默认参数的布隆过滤器,它在我们第一次add的时候自动创建。Redis也提供了可以自定义参数的布隆过滤器,只需要在add之前使用bf.reserve指令显式创建就好了。如果对应的key已经存在,bf.reserve会报错。bf.reserve有三个参数,分别是key、error_rate(错误率)和initial_size:
error_rate越低,需要的空间越大
initial_size表示预计放入的元素数量,当实际数量超过这个值时,误判率就会提升,所以需要提前设置一个较大的数值避免超出导致误判率升高;
如果不适用bf.reserve,默认的error_rate是0.01,默认的initial_size是100。

布隆过滤器的实现原理

add操作

每个布隆过滤器对应到Redis的数据结构里面就是一个大型的位数组和几个不一样的无偏 hash 函数。所谓无偏就是能够把元素的 hash 值算得比较均匀。向布隆过滤器中添加key时,会使用多个hash函数对key进行hash算得一个整数索引值然后对位数组长度进行取模运算得到一个位置,每个hash函数都会算得一个不同的位置。再把位数组的这几个位置都置为1就完成了add操作。

exists操作

exists操作跟add一样,也会把hash的几个位置都算出来,看看位数组中这几个位置是否都是1,只要有一个位为0,那么说明布隆过滤器中这个key不存在。如果都是1,这并不能说明这个key就一定存在,只是极有可能存在,因为这些位被置为1可能是因为其它的key存在所致。

如果这个位数组比较稀疏,这个概率就会很大,如果这个位数组比较拥挤,这个概率就会降低。使用时不要让实际元素远大于初始化大小,当实际元素开始超出初始化大小时,应该对布隆过滤器进行重建,重新分配一个size更大的过滤器,再将所有的历史元素批量add进去 (这就要求我们在其它的存储器中记录所有的历史元素)。因为error_rate不会因为数量超出就急剧增加,这就给我们重建过滤器提供了较为宽松的时间。

空间占用估算

计算公式:k=0.7*(l/n)          #约等于f=0.6185^(l/n)       #^表示次方计算,也就是 math.pow

布隆过滤器有两个参数,第一个是预计元素的数量n,第二个是错误率f。公式根据这两个输入得到两个输出,第一个输出是位数组的长度l,也就是需要的存储空间大小(bit),第二个输出是hash函数的最佳数量k。hash函数的数量也会直接影响到错误率,最佳的数量会有最低的错误率。

从公式中可以看出

  • 1.位数组相对越长(l/n),错误率f越低,这个和直观上理解是一致的

  • 位数组相对越长(l/n),hash函数需要的最佳数量也越多,影响计算效率

  • 当一个元素平均需要1个字节(8bit)的指纹空间时(l/n=8),错误率大约为 2%

错误率 一个元素所需平均空间 空间数
10% 4.792个bit 5bit
1% 9.585个bit 10bit
0.1% 14.377个bit 15bit

有人会问如果实际的元素超过了预算元素,错误率会如何变化,会不会错误率非常高?我们引入一个公式

f=(1-0.5^t)^k#极限近似, k 是 hash 函数的最佳数量#t表示实际元素和预计元素的倍数

错误率为 10% 时,倍数比为 2 时,错误率就会升至接近 40%
错误率为 1% 时,倍数比为 2 时,错误率升至 15%
错误率为 0.1%,倍数比为 2 时,错误率升至 5%

一名正在抢救的coder

笔名:mangolove

CSDN地址:https://blog.csdn.net/mango_love

GitHub地址:https://github.com/mangoloveYu

Redis如何实现刷抖音不重复-布隆过滤器(Bloom Filter)相关推荐

  1. Redis缓存穿透“新杀招“:布隆过滤器Bloom Filter

    场景分析 这篇文章来讲述缓存穿透的补充解决方案. 为什么要用补充来形容呢? 在之前的文章中,我们提到缓存穿透的解决方案时,我是这么说的: 关于缓存穿透,我们可以在用户访问数据库后将null值存入Red ...

  2. 硬核 | Redis 布隆(Bloom Filter)过滤器原理与实战

    在Redis 缓存击穿(失效).缓存穿透.缓存雪崩怎么解决?中我们说到可以使用布隆过滤器避免「缓存穿透」. 码哥,布隆过滤器还能在哪些场景使用呀? 比如我们使用「码哥跳动」开发的「明日头条」APP 看 ...

  3. 解放双手,自动刷抖音

    起因 因为项目需要,最近在学习appium自动化,学习中很枯燥无味,想做点能激起兴趣的事情,正好平时喜欢刷抖音,想一想能不能解放双手自动刷抖音呢,有想法咱们就行动起来,搞.搞.搞 (ps:代码很简单, ...

  4. 疫情当下,你是在家里躺着刷抖音?还是在做这些?

    2020年本来可以是很开心的一年 没想到一开头就给了我们一个重重的一击 疫情的出现让我们非常的恐慌 新型病毒肺炎让我们无处可躲 原来热闹的新年因为疫情让我们逼不得已只能待在家里 走亲访友更是不可能的 ...

  5. Win11承诺的支持安卓App终于更新了!大神教你如何在国区使用,上班刷抖音不是梦...

    晓查 发自 凹非寺 量子位 | 公众号 QbitAI 今天可能是操作系统历史上最神奇的一天,因为Windows和Android在同一天实现了互相套娃. 微软承诺的"Windows 11支持A ...

  6. 刷抖音对手机有什么要求_6频段全面5G手机 nova6 5G成新年换机最佳之选

    随着2020年的到来, 5G这趟高速列车将会"全面发车",5G网络也将会为我们带来全新的生活方式.对于追赶潮流的年轻消费者们来说,自然也想尽早坐上这趟5G列车,尝试一番5G网络.因 ...

  7. python刷抖音_用Python生成抖音字符视频!

    抖音字符视频在去年火过一段时间. 反正我是始终忘不了那段极乐净土的音乐... 这一次自己也来实现一波,做一个字符视频出来. 主要用到的库有cv2,pillow库. 原视频如下,直接抖音下载的,妥妥的水 ...

  8. 刷抖音看到 Python 工程师的工资条后,我沉默了...

    戳蓝字"CSDN云计算"关注我们哦! 最近无意中刷抖音 刷到了一个Python工程师的工资条 然后我默默的打开看了 然后我默默的关闭了 emmm..... 后悔为什么我当时没有坚持 ...

  9. 如何在Linux系统上刷抖音

    自从抖音出了网页版 很多小伙伴,上班刷起来了 今天,写一篇教大家如何使用linux刷抖音 抖音入驻PC端之后,其实就是一个终端的网站页面 看看我们如何在Linux端, 完成搜索.截图.访问网页等等功能 ...

最新文章

  1. poj2503 Babelfish
  2. Xilinx IP核之FIFO
  3. JavaScript 中的对象拷贝(深拷贝、浅拷贝)
  4. YoloV3网络模型搭建
  5. 「软件项目管理」成本估算模型——Walston-Felix模型和COCOMO Ⅱ模型
  6. linux qt显示gif图片,QT显示GIF图片
  7. python 向量取整数_随机整数向量| 使用Python的线性代数
  8. 在Emacs24下的Java环境(Cedet+Elib+JDEE+ECB)
  9. 【Pytorch】LeNet的pytorch写法
  10. Vue.js 2.6尝鲜
  11. Kubernetes 权限管理
  12. Android ANR原因以及开发时如何预防
  13. 关于使用VBA调用AutoCAD的学习
  14. Excel表Ctrl+v和Ctrl shift+v有什么区别_朴素的办公神器——excel
  15. Android.Oldboot.1,腾讯手机管家发布全球首款可根除Oldboot病毒专杀
  16. JS一些常用证件信息的正则表达式
  17. 通过cv2.resize()来改变图片大小
  18. 自由曲面光学元件的OAM测量
  19. matlab guide图像处理实例,现代数字图像处理技术提高及应用案例详解 MATLAB版-教科书.pdf...
  20. mastercam2017后处理升级_如何升级Mastercam 9.1版后处理?

热门文章

  1. lsof用法,查看端口对应的进程,运维(netstat不能用)
  2. 打印Python当前版本详细信息
  3. C/C++面试题—实现MyString类
  4. python:第一个简单爬虫程序
  5. JWT认证不通过导致不能访问视图的解决方案
  6. Data intensive Application (1)
  7. 利用scons构建project
  8. 一个渣渣的随页面滚动改变定位的代码
  9. c#中datagridview里checkbox的使用方法[转]
  10. JavaEE实战班第十二天