【SpringBoot篇】基于布隆过滤器,缓存空值,解决缓存穿透问题 (商铺查询时可用)
文章目录
- 🍔什么是缓存穿透
- 🎄解决办法
- ⭐缓存空值处理
- 🎈优点
- 🎈缺点
- 🎍代码实现
- ⭐布隆过滤器
- 🎍代码实现
🍔什么是缓存穿透
缓存穿透是指在使用缓存机制时,大量的请求无法从缓存中获取到结果,导致请求都要直接访问后端存储系统,从而增加了系统的负载和响应时间。
通常的缓存机制是将请求的结果缓存在内存或其他高速存储介质中,当相同的请求再次到达时,可以直接从缓存中获取结果,避免了从后端存储系统中读取数据的开销。
然而,在缓存穿透的情况下,由于大量请求所对应的数据在缓存中不存在,每个请求都需要直接访问后端存储系统。这可能是因为恶意请求、频繁的随机查询或者查询不存在的数据等原因。
缓存穿透可能导致以下问题:
- 性能下降:由于大量的请求都要直接访问后端存储系统,系统的响应时间会显著增加,导致性能下降。
- 增加负载:后端存储系统承受了大量无效请求的压力,增加了系统的负载,可能导致后端存储系统的性能问题。
- 安全风险:缓存穿透可能为恶意请求提供了一种绕过缓存机制直接访问后端存储系统的途径,可能导致安全漏洞或数据泄露。
🎄解决办法
- 缓存空值处理:对于不存在的数据,也将其缓存起来,但缓存的值为空,这样下次再有相同的请求到达时,可以直接返回空结果,避免对后端存储系统的重复查询。
- 布隆过滤器(Bloom Filter):使用布隆过滤器可以快速判断请求所对应的数据是否存在于缓存中,从而减少对后端存储系统的无效查询。

⭐缓存空值处理

🎈优点
实现简单,维护方便
🎈缺点
- 额外的内存消耗
- 可能造成短期数据的不一致
🎍代码实现

@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Resourceprivate CacheClient cacheClient;@Overridepublic Result queryById(Long id) {String key=CACHE_SHOP_KEY+":"+id;//从redis中查询商铺缓存String shopJson=stringRedisTemplate.opsForValue().get(key);//判断是否存在if(StrUtil.isNotBlank(shopJson)){ //isNotBlank只有传入的是 字符串 的情况下,才返回true,否则返回false//存在,直接返回Shop shop= JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//判断命中的是否是空值//因为上面isNotBlank判断了有值的情况了,下面需要判断的就2种情况 null 和 空字符串if(shopJson!=null){//不为null,那么为空字符串return Result.fail("店铺不存在!");}//不存在,根据id查询数据库Shop shop = this.getById(id);//不存在,返回错误信息if (shop == null) {//将空值写入到redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);return Result.fail("店铺不存在!");}//存在,写入到redis里面stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);//返回return Result.ok(shop);
}
⭐布隆过滤器

布隆过滤器是一种空间效率高、适合大规模数据的概率型数据结构,用于判断一个元素是否可能存在于一个集合中。布隆过滤器由一个位数组和多个哈希函数组成。其核心思想是通过多个哈希函数对输入元素进行映射,将元素映射到位数组的多个位置上,从而实现元素的快速查找。
假设布隆过滤器使用一个长度为 m 的位数组和 k 个独立的哈希函数,初始时所有位都置为 0。当要插入一个元素时,将该元素经过 k 个哈希函数得到的 k 个哈希值作为索引,在位数组中将这 k 个位置的值置为 1。当要查询一个元素时,同样将该元素经过 k 个哈希函数得到的 k 个哈希值作为索引,并检查对应的位数组位置是否都为 1,若有任何一个位置为 0,则可以确定该元素不存在于集合中;若都为 1,则该元素可能存在于集合中。
布隆过滤器的优势在于具有较高的空间效率和查询效率,适合大规模数据的情况。由于使用了多个哈希函数,可以有效减少冲突的概率,降低误判率。然而,布隆过滤器也存在一定的缺陷,即可能出现误判(即判断某个元素存在于集合中,但实际上并不存在),这是由于不同元素经过哈希函数映射后的索引可能存在冲突。因此,在使用布隆过滤器时需要权衡误判率和空间利用率。
总的来说,布隆过滤器通过位数组和多个哈希函数实现了高效的元素判断,是一种适合大规模数据场景下的概率型数据结构
🎍代码实现
实现引入依赖
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>29.0-jre</version></dependency>
配置启动类
编写核心代码

@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate BloomFilter<Long> bloomFilter;@Overridepublic Result queryById(Long id) {String key = CACHE_SHOP_KEY + ":" + id;// 使用布隆过滤器判断缓存键是否存在if (!bloomFilter.mightContain(id)) {// 缓存键不存在,直接返回错误信息return Result.fail("店铺不存在!");}// 从redis中查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(key);// 判断是否存在if (StrUtil.isNotBlank(shopJson)) {// 存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 不存在,根据id查询数据库Shop shop = this.getById(id);// 不存在,返回错误信息if (shop == null) {// 将空值写入到redisstringRedisTemplate.opsForValue().set(key, "", CACHE_SHOP_TTL, TimeUnit.MINUTES);// 将缓存键加入布隆过滤器bloomFilter.put(id);return Result.fail("店铺不存在!");}// 存在,写入到redis里面stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);// 将缓存键加入布隆过滤器bloomFilter.put(id);// 返回return Result.ok(shop);}

更加详细的布隆过滤器讲解,请参考我的Redis专栏Redis专栏里面讲解布隆过滤器的文章
在技术的道路上,我们不断探索、不断前行,不断面对挑战、不断突破自我。科技的发展改变着世界,而我们作为技术人员,也在这个过程中书写着自己的篇章。让我们携手并进,共同努力,开创美好的未来!愿我们在科技的征途上不断奋进,创造出更加美好、更加智能的明天!

相关文章:
【SpringBoot篇】基于布隆过滤器,缓存空值,解决缓存穿透问题 (商铺查询时可用)
文章目录 🍔什么是缓存穿透🎄解决办法⭐缓存空值处理🎈优点🎈缺点🎍代码实现 ⭐布隆过滤器🎍代码实现 🍔什么是缓存穿透 缓存穿透是指在使用缓存机制时,大量的请求无法从缓存中获取…...
Gitlab基础篇: Gitlab docker 安装部署、Gitlab 设置账号密码
文章目录 1、环境准备2、配置1)、初始化2)、修改gitlab配置文件3)、修改docker配置的gitlab默认端口 gitlab进阶配置gitlab 设置账号密码 1、环境准备 安装docker gitlab前确保docker环境,如果没有搭建docker请查阅“Linux docker 安装文档” docker 下载 gitlab容…...
c++常见函数处理
1、clamp clamp:区间限定函数 int64_t a Clamp(a, MIN_VALUE, MAX_VALUE); #include <iomanip> #include <iostream> #include <sstream>int main() {std::cout << "no setw: [" << 42 << "]\n"<&l…...
MYsql第二次作业
目录 问题 解答 1.显示所有职工的基本信息。 2.查询所有职工所属部门的部门号,不显示重复的部门号。 3.求出所有职工的人数。 4.列出最高工和最低工资。 5.列出职工的平均工资和总工资。 6.创建一个只有职工号、姓名和参加工作的新表,名为工作日…...
SQLAlchemy 第三篇
使用insert语句 from sqlalchemy import Table, Column, Integer, String, MetaDatametadata_obj MetaData() user_table Table("user_account",metadata_obj,Column("id", Integer, primary_keyTrue),Column("name", String(255)),Column(&q…...
交互过程中影响信息质量好坏的因素
人机交互是指人与计算机之间的交流和互动,而人人交流是指人与人之间的交流和互动。在信息质量方面,人机交互通常更为准确和精确,而人人交流可能存在误解、模糊和歧义。 人机交互的信息传递往往通过明确的界面、符号和指令等方式进行。计算机可…...
服务器上配置jupyter,提示Invalid credentials如何解决
我是按照网上教程在服务器上安装的jupyter以及进行的密码配置,我利用 passwd()这个口令生成的转译密码是"argon...."。按照教程配置jupyter notebook配置文件里面的内容,登陆网页提示"Invalid credentials"。我谷歌得到的解答是&…...
Axure中动态面板使用及轮播图多种登录方式左侧导航栏之案列
🎬 艳艳耶✌️:个人主页 🔥 个人专栏 :《产品经理如何画泳道图&流程图》 ⛺️ 越努力 ,越幸运 目录 一、轮播图简介 1、什么是轮播图 2、轮播图有什么作用 3、轮播图有什么特点 4、轮播图适应范围 5、…...
大数据之旅-问题反思
1.谈谈你对MR执行流程各个阶段的理解(提示里面涉及到排序,快速排序或者归并排序知道两种实现形式)? 2.hadoop 1.0和hadoop 2.0明显的差异如何理解? hadoop2.0与hadoop1.0区别体现在在架构、性能、功能和组件方面&…...
系统级基础信号知识【Linux】
目录 一,什么是信号 进程面对信号常见的三种反应概述 二,产生信号 1.终端按键产生信号 signal 2. 进程异常产生信号 核心转储 3. 系统调用函数发送信号 kill raise abort 小结: 4. 由软件条件产生 alarm 5. 硬件异常产生信号…...
Excel单元格隐藏如何取消?
Excel工作表中的有些单元格隐藏了数据,如何取消隐藏行列呢?今天分享几个方法给大家 方法一: 选中隐藏的区域,点击右键,选择【取消隐藏】就可以了 方法二: 如果工作表中有多个地方有隐藏的话,…...
Visual Studio(VS)常用快捷键(最详细)
Visual Studio常用快捷键 一、生成:常用快捷键二、调式:常用快捷键三、编辑:常用快捷键四、文件:常用快捷键五、项目:常用快捷键六、重构:常用快捷键七、工具:常用快捷键八、视图:常…...
UDP特性之组播(多播)
UDP特性之组播 1. 组播的特点2. 设置主播属性2.1 发送端2.2 接收端 3. 组播通信流程3.1 发送端3.2 接收端 4. 通信代码 原文链接 在公司测试广播和多播有一点问题。。。 1. 组播的特点 组播也可以称之为多播这也是UDP的特性之一。组播是主机间一对多的通讯模式,是…...
ElasticSearch之cat shards API
命令样例如下: curl -X GET "https://localhost:9200/_cat/shards?vtrue&pretty" --cacert $ES_HOME/config/certs/http_ca.crt -u "elastic:ohCxPHQBEs5*lo7F9"执行结果输出如下: index shard prirep state docs s…...
Thread-Per-Message设计模式
Thread-Per-Message是为每一个消息的处理开辟一个线程,以并发方式处理,提高系统整体的吞吐量。这种模式再日常开发中非常常见,为了避免线程的频繁创建和销毁,可以使用线程池来代替。 示例代码如下: public class Requ…...
运筹学经典问题(一):指派问题
问题描述 有 N N N个任务,需要 N N N个人去完成,每个人完成不同工作的效率不同(或者资源、收益等等),需要怎么分配使得整体的效率最高(成本最低等等)呢?这就是经典的指派问题啦&…...
产品经理之如何编写竞品分析(医疗HIS系统管理详细案例模板)
目录 一.项目周期 二.竞品分析的目的 三.竞品分析包含的维度 四.如何选择竞品 五.竞品画布 六.案例模板 一.项目周期 在整个项目的周期,产品经理所做的事情主要在项目前期做市场分析、需求调研等,下面一张图概况了整个项目周期产品经理、开发工程师…...
虚拟内存管理
虚拟内存管理 页面置换算法 功能和目标: 功能:当缺页中断发生,需要调入新的页面而内存已经满时,选择内存当中哪个物理页面被置换。目标:尽可能的减少页面的换进换出次数(即缺页中断的次数)。具…...
ssh时怎么同时指定其端口号,以及scp文件到远程的指定端口
如果想要通过 SSH 连接到指定端口的远程服务器,可以在 SSH 命令中使用 -p 或 --port 参数来指定端口号。以下是相应的用法: $ ssh -p <port> userhost其中, 是要连接的端口号,user 是远程服务器上的用户名,host…...
Redis过期淘汰策略
一. Redis过期淘汰策略 当Redis已用内存超过maxmemory限定时,触发主动清理策略。 主动清理策略在Redis 4.0之前一共实现了 6 种内存淘汰策略,在 4.0 之后,又增加了 2 种 策略,总共8种: 针对设置了过期时间的key做处理…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

