1. 布隆过滤器

1.1 概念

在架构设计时有一种最常见的设计被称为布隆过滤器,它可以有效减少缓存穿透的情况。其主旨是采用一个很长的二进制数组,通过一系列的 Hash 函数来确定该数据是否存在。

布隆过滤器本质上是一个 n 位的二进制数组。你也知道二进制只有 01 来表示,针对于当前我们的场景。这里我模拟了一个二进制数组,其每一位它的初始值都是 0

而这个二进制数组会被存储在 Redis 服务器中,那么这个数组该怎么用呢?

1.2 原理

使用若干次 Hash 来确定其位置。

假设有 1000 个商品编号,从 1~1000。作为布隆过滤器,在初始化的时候,实际上就是对每一个商品编号进行若干次 Hash 来确定它们的位置。

(1)1 号商品计算
比如说针对于当前的“1”编号,我们对其执行了三次 Hash。所谓 Hash 函数就是将数据代入以后确定一个具体的位置。

Hash 1 函数:它会定位到二进制数组的第 2 位上,并将其数值从 0 改为 1;

Hash 2 函数:它定位到索引为 5 的位置,并将从 0 改为 1;

Hash 3 函数:定位到索引为 99 的位置上,将其从 0 改为 1。

(2)2 号商品计算
那 1 号商品计算完以后,该轮到 2 号商品。2 号商品经过三次 Hash 以后,分别定位到索引为 1、3 以及 98 号位置上。
原始数据中 1 号位因为刚才已经变成了 1,现在它不变;而 3 号位和 98 号位原始数据从 0 变为 1。

这里又衍生出一个 Hash 新规则:如果在 Hash 后,原始位它是 0 的话,将其从 0 变为 1;如果本身这一位就是 1 的话,则保持不变。

(3)1000 号商品计算
此时 2 号商品也处理完了,我们继续向后 3、4、5、6、7、8 直到编号达到了最后一个 1000,当商品编号 1000 处理完后,他将索引为 3、6、98 设置为 1。

2. 布隆过滤器在电商商品中的实践

(1)先看一个已存在的情况
比如,此时某一个用户要查询 858 号商品数据。都知道 858 是存在的,那么按照原始的三个 Hash 分别定位到了 1、5 和 98 号位,当每一个 Hash 位的数值都是 1 时,则代表对应的编号它是存在的。
(2)再看一个不存在的情况
例如这里要查询 8888。8888 这个数值经过三次 Hash 后,定位到了 3、6 和 100 这三个位置。此时索引为 100 的数值是 0,在多次 Hash 时有任何一位为 0 则代表这个数据是不存在的。

简单总结一下:如果布隆过滤器所有 Hash 的值都是 1 的话,则代表这个数据可能存在。
注意我的表达:它是可能存在;但如果某一位的数值是 0 的话,它是一定不存在的。

布隆过滤器设计之初,它就不是一个精确的判断,因为布隆过滤器存在误判的情况。

(3)最后看一个误判情况
来看一下当前的演示:比如现在我要查询 8889 的情况,经过三次 Hash 正好每一位上都是 1。尽管在数据库中,8889 这个商品是不存在的;但在布隆过滤器中,它会被判定为存在。这就是在布隆过滤器中会出现的小概率的误判情况。

3. 如何减少布隆过滤器的误判

关于减少误判的产生,方法有两个:

  • 第一个是增加二进制位数。在原始情况下我们设置索引位到达了 100,但是如果我们把它放大 1 万倍,到达了 100 万,是不是 Hash 以后的数据会变得更分散,出现重复的情况就会更小。

  • 第二个是增加 Hash 的次数。其实每一次 Hash 处理都是在增加数据的特征,特征越多,出现误判的概率就越小。

现在我们是做了三次 Hash,那么如果你做十次,是不是它出现误判的概率就会小非常多?但是在这个过程中,代价便是 CPU 需要进行更多运算,这会让布隆过滤器的性能有所降低。

4. 布隆过滤器在 Java 中的应用

Java 中提供了一个 Redisson 的组件,它内置了布隆过滤器,可以让程序员非常简单直接地去设置布隆过滤器。
上面代码是 Redisson 的使用办法,在前几行代码,用来设置 Redis 服务器的服务地址及端口号。

而后面关键的地方在这里,我们实例化一个布隆过滤器对象,后面的参数指代 Redis 使用哪个 key 来保存布隆过滤器数据?

下面这句话非常关键,作为当前的布隆过滤器,这里需要调用 tryInit 方法,它有两个参数:

  • 第一个参数是代表初始化的布隆过滤器长度,长度越大,出现误判的可能性就越低。

  • 而第二个 0.01 则代表误判率最大允许为 1%,在我们以前的项目中通常也是设置为 1%。如果把这个数值设置太小,虽然会降低误判率,但会产生更多次的 Hash 操作,会降低系统的性能(正是刚刚讲过的),因此 1% 也是我所建议的数值。

当把布隆过滤器初始化以后,我们便可以通过 add 方法,往里边去添加数据。所谓添加数据,就是将数据进行多次 Hash,将对应位从 0 变为 1 的过程。例如,现在我们把编号 1 增加进去,之后可以通过布隆过滤器的 contains 方法来判断当前这个数据是否存在。

我们输入 1,它输出 true;而输入了不存在的 8888,则输出 false
请注意:这两个结果的含义是不同的。

  • 如果输出 false,则代表这个数据它是肯定不存在的;
  • 但是如果输出 true 的时候,它有 1% 的概率可能不存在,因为布隆过滤器它存在误判的情况。

5. 布隆过滤器在项目中的应用

布隆过滤器在项目中的使用流程,其实就归结成以下三部分:

  • 第一个部分是在应用启动时,我们去初始化布隆过滤器。例如将 1000 个、1 万个、10 万个商品进行初始化,完成从 0 到 1 的转化工作。

  • 之后便是当用户发来请求时,会附加商品编号,如果布隆过滤器判断编号存在,则直接去读取存储在 Redis 缓存中的数据;如果此时 Redis 缓存没有存在对应的商品数据,则直接去读取数据库,并将读取到的信息重新载入到 Redis 缓存中。这样下一次用户在查询相同编号数据时,就可以直接读取缓存了。

  • 另外一种情况是,如果布隆过滤器判断没有包含编号,则直接返回数据不存在的消息提示,这样便可以在 Redis 层面将请求进行拦截。

你可能会有疑惑,既然布隆过滤器存在误判率,那出现了误判该怎么办呢?

其实在大多数情况下,我们出现误判也不会对系统产生额外的影响。因为像刚才我们设置 1% 的误判率,1 万次请求才可能会出现 100 次误判的情况。我们已经将 99% 的无效请求进行了拦截,而这些漏网之鱼也不会对我们系统产生任何实质影响。

6. 初始化后,对应商品被删怎么办

假如布隆过滤器初始化后,对应商品被删除了,该怎么办呢?这是一个布隆过滤器的小难点。

因为布隆过滤器某一位的二进制数据,可能被多个编号的 Hash 位进行引用。比如说,布隆过滤器中 2 号位是 1,但是它可能被 3、5、100、1000 这 4 个商品编号同时引用。这里是不允许直接对布隆过滤器某一位进行删除的,否则数据就乱了,怎么办呢?

这里业内有两种常见的解决方案:

  • 定时异步重建布隆过滤器。比如说我们每过 4 个小时在额外的一台服务器上,异步去执行一个任务调度,来重新生成布隆过滤器,替换掉已有的布隆过滤器。

  • 计数布隆过滤器。在标准的布隆过滤器下,是无法得知当前某一位它是被哪些具体数据进行了引用,但是计数布隆过滤器它是在这一位上额外的附加的计数信息,表达出该位被几个数据进行了引用。

7. 总体概览

原文:
原文链接

Redis 预防缓存穿透“神器” — 布隆过滤器相关推荐

  1. 解决Redis缓存穿透之布隆过滤器详解

    文章目录 1. 什么是Bloom Filter(布隆过滤器) 1.1 布隆过滤器优点 1.2 布隆过滤器缺点 1.3 布隆过滤器使用场景 1.4 布隆过滤器检索过程 1.5 布隆过滤器的算法描述 2. ...

  2. Redis专题-缓存穿透、缓存雪崩、缓存击穿

    一.缓存穿透 缓存穿透概念 缓存穿透是指查询一个一定不存在的数据,在数据库没有,自然在缓存中也不会有.导致用户查询的时候,在缓存中找不到对应key的value,每次都要去数据库再查询一遍,如果从存储层 ...

  3. 防缓存穿透利器-布隆滤器(BloomFilter)

    一.布隆过滤器原理 如果想要判断一个元素是不是在一个集合中存在,一般的想法是将所有元素保存起来,然后再拿着这个元素在集合中一个一个进行比对.但是随着集合中元素的增加,我们需要的存储空间越来越大,检索速 ...

  4. Redis:缓存穿透、缓存雪崩和缓存击穿

    Redis的缓存穿透.缓存雪崩和缓存击穿 一. 缓存穿透 1.1 概念 1.3 解决方案 1.4 案例:查询商铺信息(缓存穿透的实现) 二. 缓存雪崩 2.1 概念 2.2 解决方案 三. 缓存击穿( ...

  5. Redis解决缓存穿透问题

    文章目录 Redis解决缓存穿透问题 什么是缓存穿透 解决方法 Redis解决缓存穿透问题 什么是缓存穿透 请看图,当我们用户访问我们的服务器的时候,服务器一般会先访问我们的redis,查看我们的缓存 ...

  6. redis的缓存穿透如何解决!

    redis的高频面试题(开发一定会用到) redis的缓存穿透,如何解决?所谓的缓存穿透:在客户端去查询数据的时候,数据库中没有数据,缓存中也没有,按照redis源码的执行流程这就会出现情况--> ...

  7. 高并发下的缓存问题及布隆过滤器

    一. 高并发下缓存的三大问题 1. 概述 背景 在高并发场景下,如果系统直连数据库,数据库会出现性能问题,甚至造成数据库宕机,服务不可用. 为了降低数据库的压力,我们通常会设计一个缓存系统,在访问数据 ...

  8. Redis bitmap、hyperlog、布隆过滤器、RoaringBitmap原理应用场景与日活的统计的具体应用

    传统方案-mysql 缺点: 1.空间占用大 2.统计逻辑复杂,比如 统计最近 30 天用户的累计活跃天(每个用户在 30 天里有 N 天使用 app,N 为 1-30,然后将月活跃用户的 N 天加总 ...

  9. redis的缓存穿透 雪崩击穿

    缓存穿透: 由于失误或其他原因去查询不存在的key,请求量又非常大,那么在外部看来突然有大量的查询在你的系统当中,缓存又根本没有生效,越过缓存,疯狂查数据库,查数据库对系统压力非常大,效率比redis ...

最新文章

  1. 【Spark Summit EU 2016】使用Spark轻松获取高产量基因组
  2. AD9833所产生的高频信号质量分析
  3. marbin mysql_跨浏览器图像灰度(grayscale)解决方案
  4. linux python版本升级和系统更新_Linux 下升级python和安装pip
  5. SpringBoot————快速搭建springboot项目
  6. openstack kvm 虚拟机磁盘差异衍生
  7. 计算机应用与技术大赛,关于举办2017年燕山大学第一届计算机应用技术与程序设计大赛的通知...
  8. Oracle11g新特性:在线操作功能增强-表增加包含默认值的字段(转载)
  9. 62. 不同路径(JavaScript)
  10. java添加录音,大家说说java程序里怎么插入视频和音频啊
  11. Ubuntu16.04 + Digits + caffee
  12. QT中widget相关控件
  13. 原生js追加html代码,原生js动态添加元素
  14. 赤峰中考计算机考试软件,2017年内蒙古赤峰中考信息技术操作考试实施细则
  15. Linux入门怎么学?262页linux学习笔记,零基础也能轻松入门
  16. Midjourney|文心一格prompt教程[Text Prompt(下篇)]:游戏、实物、人物、风景、动漫、邮票、海报等生成,终极模板教学
  17. KDD 2011 最佳工业论文中机器学习的实践方法-翻译
  18. c++某商店开展买一送一活动,购买两件商品时,只需支付价格较高的商品的金额。要求程序在输入两个商品的价格后,输出所应支付的金额,请根据裁判程序编写函数cut,将代码补充完整。
  19. Reds3配置文件详解
  20. [51nod1326]遥远的旅途

热门文章

  1. 2022-2028年中国床上用品行业投资分析及前景预测报告
  2. 2022-2028年中国农副产品行业市场供需规模及未来前景分析报告
  3. Go 知识点(15)— 切片长度和容量
  4. 前端Vue学习之路(一)-初识Vue
  5. 只要5分钟用数据可视化带你看遍11月份新闻热点事件
  6. axmath公式编辑器
  7. LeetCode简单题之将整数转换为两个无零整数的和
  8. LeetCode简单题之复写零
  9. Linux实现ffmpeg H.265视频编码
  10. 操作系统常用词典(一)