防缓存穿透利器-布隆滤器(BloomFilter)
布隆过滤器
1、布隆过滤器原理
1.1 什么是布隆过滤器
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。
主要用于判断一个元素是否在一个集合中,0代表不存在某个数据,1代表存在某个数据。
总结: 一个元素一定不存在 或者 可能存在! 存在一定的误判率{通过代码调节}
1.2 使用场景
大数据量的时候, 判断一个元素是否在一个集合中。解决缓存穿透问题
1.3 原理
存入过程
布隆过滤器上面说了,就是一个二进制数据的集合。当一个数据加入这个集合时,经历如下:
通过K个哈希函数计算该数据,返回K个计算出的hash值
这些K个hash值映射到对应的K个二进制的数组下标
将K个下标对应的二进制数据改成1。
例如,第一个哈希函数返回x,第二个第三个哈希函数返回y与z,那么: X、Y、Z对应的二进制改成1。
如图所示:

查询过程
布隆过滤器主要作用就是查询一个数据,在不在这个二进制的集合中,查询过程如下:
1、通过K个哈希函数计算该数据,对应计算出的K个hash值
2、通过hash值找到对应的二进制的数组下标
3、判断:如果存在一处位置的二进制数据是0,那么该数据不存在。如果都是1,该数据存在集合中。
1.4 布隆过滤器的优缺点
- 优点
- 由于存储的是二进制数据,所以占用的空间很小
- 它的插入和查询速度是非常快的,时间复杂度是O(K),空间复杂度:O (M)。
K: 是哈希函数的个数
M: 是二进制位的个数
- 保密性很好,因为本身不存储任何原始数据,只有二进制数据
- 缺点:
添加数据是通过计算数据的hash值,那么很有可能存在这种情况:两个不同的数据计算得到相同的hash值。

例如图中的“张三”和“张三丰”,假如最终算出hash值相同,那么他们会将同一个下标的二进制数据改为1。
这个时候,你就不知道下标为1的二进制,到底是代表“张三”还是“张三丰”。
由此得出以下缺点:
1、存在误判
假如上面的图没有存 “张三”,只存了 “张三丰”,那么用"张三"来查询的时候,会判断"张三"存在集合中。
因为“张三”和“张三丰”的hash值是相同的,通过相同的hash值,找到的二进制数据也是一样的,都是1。
误判率:
受三个因素影响: 二进制位的个数m, 哈希函数的个数k, 数据规模n (添加到布隆过滤器中的数据)

已知误判率p, 数据规模n, 求二进制的个数m,哈希函数的个数k {m,k 程序会自动计算 ,你只需要告诉我数据规模,误判率就可以了}

ln: 自然对数是以常数e为底数的对数,记作lnN(N>0)。在物理学,生物学等自然科学中有重要的意义,一般表示方法为lnx。数学中也常见以logx表示自然对数。
2、删除困难
还是用上面的举例,因为“张三”和“张三丰”的hash值相同,对应的数组下标也是一样的。
如果你想去删除“张三”,将下标为1里的二进制数据,由1改成了0。
那么你是不是连“张三丰”都一起删了。
2、实现方式
2.1 初始化skuId的布隆过滤器
我在service-product模块中操作
2.1.1 RedisConst常量类
public class RedisConst {
public static final String SKUKEY_PREFIX = "sku:";
public static final String SKUKEY_SUFFIX = ":info";
//单位:秒
public static final long SKUKEY_TIMEOUT = 24 * 60 * 60;
// 定义变量,记录空对象的缓存过期时间
public static final long SKUKEY_TEMPORARY_TIMEOUT = 10 * 60;
//单位:秒 尝试获取锁的最大等待时间
public static final long SKULOCK_EXPIRE_PX1 = 100;
//单位:秒 锁的持有时间
public static final long SKULOCK_EXPIRE_PX2 = 10;
public static final String SKULOCK_SUFFIX = ":lock";
public static final String USER_KEY_PREFIX = "user:";
public static final String USER_CART_KEY_SUFFIX = ":cart";
public static final long USER_CART_EXPIRE = 60 * 60 * 24 * 30;
//用户登录
public static final String USER_LOGIN_KEY_PREFIX = "user:login:";
// public static final String userinfoKey_suffix = ":info";
public static final int USERKEY_TIMEOUT = 60 * 60 * 24 * 7;
//秒杀商品前缀
public static final String SECKILL_GOODS = "seckill:goods";
public static final String SECKILL_ORDERS = "seckill:orders";
public static final String SECKILL_ORDERS_USERS = "seckill:orders:users";
public static final String SECKILL_STOCK_PREFIX = "seckill:stock:";
public static final String SECKILL_USER = "seckill:user:";
//用户锁定时间 单位:秒
public static final int SECKILL__TIMEOUT = 60 * 60 * 1;
// 布隆过滤器使用!
public static final String SKU_BLOOM_FILTER="sku:bloom:filter";
}
123456789101112131415161718192021222324252627282930313233343536
2.1.2 修改启动类
@SpringBootApplication
@ComponentScan({"com.atguigu.gmall"})
@EnableDiscoveryClient
public class ServiceProductApplication implements CommandLineRunner {
@Autowired
private RedissonClient redissonClient;
public static void main(String[] args) {
SpringApplication.run(ServiceProductApplication.class,args);
}
//初始化布隆过滤器
@Override
public void run(String... args) throws Exception {
//获取布隆过滤器
RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConst.SKU_BLOOM_FILTER);
//初始化布隆过滤器:计算元素的数量 比如预计有多少个sku
bloomFilter.tryInit(10001,0.001);
}
}
123456789101112131415161718192021
2.2 给商品详情页添加布隆过滤器
1、查看商品详情页添加布隆过滤器
操作模块:service-item
更改ItemserviceImpl.item方法

2、添加商品sku加入布隆过滤器数据
操作模块:service-product
更改ManageServiceImpl.saveSkuInfo方法

这样就避免了别人用一个不存在的key去疯狂攻击我们的缓存数据库。
我们在分布式锁中将查询结果是null的也进行缓存,但是如果有人用随机数去疯狂请求我们的接口,那我们的Redis可能会扛不住,所以在这里用布隆过滤器,只需要在初始化的时候,指定我们存储数据的数据量和可以承受的误判率即可。
布隆过滤器指导有哪些数据,这样别人使用随机数攻击的时候直接就给他返回,不用再去查Redis了。
防缓存穿透利器-布隆滤器(BloomFilter)的更多相关文章
- Redis缓存穿透问题及解决方案
上周在工作中遇到了一个问题场景,即查询商品的配件信息时(商品:配件为1:N的关系),如若商品并未配置配件信息,则查数据库为空,且不会加入缓存,这就会导致,下次在查询同样商品的配件时,由于缓存未命中,则 ...
- Redis缓存穿透和缓存雪崩以及解决方案
Redis缓存穿透和缓存雪崩以及解决方案 Redis缓存穿透和缓存雪崩以及解决方案缓存穿透解决方案布隆过滤缓存空对象比较缓存雪崩解决方案保证缓存层服务高可用性依赖隔离组件为后端限流并降级数据预热缓存并 ...
- Redis: 缓存过期、缓存雪崩、缓存穿透、缓存击穿(热点)、缓存并发(热点)、多级缓存、布隆过滤器
Redis: 缓存过期.缓存雪崩.缓存穿透.缓存击穿(热点).缓存并发(热点).多级缓存.布隆过滤器 2019年08月18日 16:34:24 hanchao5272 阅读数 1026更多 分类专栏: ...
- Bloom Filter(布隆过滤器)如何解决缓存穿透
本文摘抄自我的微信公众号"程序员柯南",欢迎关注!原文阅读 缓存穿透是什么? 关于缓存穿透,简单来说就是系统处理了大量不存在的数据查询.正常的使用缓存流程大致是,数据查询先进行缓存 ...
- redis缓存穿透穿透解决方案-布隆过滤器
redis缓存穿透穿透解决方案-布隆过滤器 我们先来看一段代码 cache_key = "id:1" cache_value = GetValueFromRedis(cache_k ...
- Redis缓存穿透、缓存雪崩、redis并发问题 并发竞争key的解决方案 (阿里)
阿里的人问我 缓存雪崩(大量数据在同一时间过期了)了如何处理,缓存击穿了如何处理,回答的很烂,做了总结: 把redis作为缓存使用已经是司空见惯,但是使用redis后也可能会碰到一系列的问题,尤其是数 ...
- redis缓存雪崩、缓存穿透、数据库和redis数据一致性
一.缓存雪崩 回顾一下我们为什么要用缓存(Redis):减轻数据库压力或尽可能少的访问数据库. 在前面学习我们都知道Redis不可能把所有的数据都缓存起来(内存昂贵且有限),所以Redis需要对数据设 ...
- Redis基础用法、高级特性与性能调优以及缓存穿透等分析
一.Redis介绍 Redis是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库.缓存服务或消息服务使用.Redis支持多种数据结构,包括字符串.哈希表.链表.集合.有序集合.位图.Hype ...
- 缓存与数据库一致性之三:缓存穿透、缓存雪崩、key重建方案
一.缓存穿透预防及优化 缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,但是出于容错的考虑,如果从存储层查不到数据则不写入缓存层,如图 11-3 所示整个过程分为如下 3 步: 缓存层 ...
- Redis缓存雪崩、缓存穿透、热点Key解决方案和分析
缓存穿透 缓存系统,按照KEY去查询VALUE,当KEY对应的VALUE一定不存在的时候并对KEY并发请求量很大的时候,就会对后端造成很大的压力. (查询一个必然不存在的数据.比如文章表,查询一个不存 ...
随机推荐
- 【LeetCode动态规划#11】打家劫舍系列题(涉及环结构和树形DP的讨论)
打家劫舍 力扣题目链接(opens new window) 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻 ...
- .NET周报 【4月第4期 2023-04-23】
国内文章 2023成都.NET线下技术沙龙圆满结束 https://www.cnblogs.com/edisonchou/p/2023_chengdu_dotnet_club_activity_rev ...
- 推荐两个AI神器:ChatGPT只需1个标题,2分钟全自动生成PPT!
今天给大家分享两个工具,帮助你全自动生成PPT,接下来以自动化测试为主题,教大家如何2分钟生成好PPT. 1.第一个工具:ChatGPT 1.打开ChatGPT页面,输入prompt,告诉它,让它帮你 ...
- 【Redis】持久化实现(RDB、AOF)
一.Redis RDB 持久化 1.RDB 工作原理 RDB(Redis Database)基于时间进行生成数据快照,默认只保留当前最新数据状态,优点时执行速度较快,但上次数据保存点到当前时间点之间的 ...
- 【漏洞分析】ReflectionToken BEVO代币攻击事件分析
前言 BEVO代币是一种Reflection Token(反射型代币),并且拥有通缩的特性.关于Reflection Token更为详细的说明可参考这篇文章.然后目前浏览到的很多分析报告没有指出其漏洞 ...
- 1406, "Data too long for column 'od_seq' at row 1"
问题描述:1406, "Data too long for column 'od_seq' at row 1" 问题分析:录入数据长度超出字段的最大限制 解决方法:增加max_le ...
- phpstudy-sqlilabs-less-11
题目:POST - Error Based - Single quotes- String 基于错误的单引号post型字符变形的注入 看到有个账密输入口第一反应尝试post注入 打开post data ...
- 2022年第十四届四川省大学生程序设计大赛 A
A Adjacent Swapping 题意: 给定一个字符串,每次可以移动相邻字符,求最小移动次数可以把它变成s+s这样左右两边相同的字符串. 思路: 1:我们知道他一定是偶数长度,所以我们把字符串 ...
- MAUI Android 关联文件类型
实现效果 打开某个文件,后缀是自己想要的类型,在弹出的窗口(用其它应用打开)的列表中显示自己的应用图标 点击后可以获得文件信息以便于后续的操作 实现步骤 以注册.bin后缀为例,新建一个MAUI项目 ...
- 在.net项目中添加Husky.Net提交验证
参考:C# 项目添加 husky - jesn - 博客园 (cnblogs.com) 官方文档:Getting Started | Husky.Net (alirezanet.github.io) ...