Redis-缓存穿透击穿雪崩

1. 穿透问题

缓存穿透问题就是查询不存在的数据。在缓存穿透中,先查缓存,缓存没有数据,就会请求到数据库上,导致数据库压力剧增。

解决方法:

  1. 给不存在的key加上空值,防止每次都会请求到数据库。
  2. 布隆过滤器,做一次过滤

1.1 使用缓存空值解决缓存击穿问题

  1. 根据id=1来请求
  2. redis存在数据
    2.1. 存储的是空值{},那么返回null
    2.2. 存储的不是空值,说明存储的是真实的数据库数据
  3. redis不存在数据
  4. 查询数据库
    4.1. 数据库存在数据,那么缓存数据到redis,返回真实的数据
    4.2. 数据库不存在数据,那么缓存空对象 {},设置一个过期时间,返回空

@Component
public class RedisCacheClient {private final StringRedisTemplate stringRedisTemplate;public RedisCacheClient(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}private void set(String key, Object value, Long time, TimeUnit timeUnit) {stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, timeUnit);}private String get(String key) {return stringRedisTemplate.opsForValue().get(key);}public <ID, R> R queryWithPassThrough(String keyPrefix, ID id, Class<R> clazz,Function<ID, R> dbFallBack, Long time, TimeUnit unit) {String key = keyPrefix + id;// 1.从redis查询数据String json = get(key);// 2.判断数据是否存在if (RedisConstants.EMPTY_OBJECT_JSON.equals(json)) {return null; //缓存的空对象值}if (StrUtil.isNotEmpty(json)) {return JSONUtil.toBean(json, clazz);}// 3.不存在,根据id查询数据库R r = dbFallBack.apply(id);if (r != null) {set(key, r, time, unit);return r;}// 4.存储空对象set(key, RedisConstants.EMPTY_OBJECT_JSON /*{}*/, RedisConstants.CACHE_NULL_TTL, TimeUnit.SECONDS);return null;}
}

1.2 使用布隆过滤器做初次判断

对于恶意攻击,向服务器请求大量不存在的数据造成的缓存穿透,还可以用布隆过滤器先做一次过滤,对于不存在的数据,布隆过滤器一般都能够过滤掉,不让请求再往后端发送。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。

在这里插入图片描述

布隆过滤器就是一个大型的位数组和几个不一样的无偏 hash 函数。所谓无偏就是能够把元素的 hash 值算得比较均匀。

向布隆过滤器中添加 key 时,会使用多个 hash 函数对 key 进行 hash 算得一个整数索引值然后对位数组长度 进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就 完成了 add 操作。向布隆过滤器询问 key 是否存在时,跟 add 一样,也会把 hash 的几个位置都算出来,看看位数组中这几个位置是否都为 1,只要有一个位为 0,那么说明布隆过滤器中这个key 不存在。如果都是 1,这并不能说明这个key 就一定存在,只是极有可能存在,因为这些位被置为 1 可能是因为其它的 key 存在所致。如果这个位数组比较稀疏,这个概率就会很大,如果这个位数组比较拥挤,这个概率就会降低。

这种方法适用于数据命中不高、 数据相对固定、 实时性低(通常是数据集较大) 的应用场景, 代码维护较为复杂, 但是缓存空间占用很少。


1.2.1 导入pom坐标
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.13.6</version>
</dependency>
1.2.2 布隆过滤器代码示例
class Main {private RedissonClient redissonClient;void test() {RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("orderList");// 1.初始化布隆过滤器:预计元素为100000000L,误判率为3%,根据这两个参数会计算出底层的bit数组大小bloomFilter.tryInit(100000000L, 0.03);// 2.添加元素到bloomFilterbloomFilter.add("ayuan");// 3.判断下面的数据是否在布隆过滤器中System.out.println(bloomFilter.contains("asheng"));System.out.println(bloomFilter.contains("longge"));System.out.println(bloomFilter.contains("ayuan"));}
}

使用布隆过滤器需要把所有数据提前放入布隆过滤器,并且在增加数据时也要往布隆过滤器里放,布隆过滤器缓存过滤伪代码:
在这里插入图片描述

1.2.3 布隆过滤器实战
class Main {@Autowiredprivate RedissonClient redissonClient;private RBloomFilter<String> bloomFilter;@PostConstructvoid init() {// 1.初始化布隆过滤器bloomFilter = redissonClient.getBloomFilter("orderList");// 初始化布隆过滤器:预计元素为100000000L,误判率为3%,根据这两个参数会计算出底层的bit数组大小bloomFilter.tryInit(100000000L, 0.03);// 2.加载所有的数据加载到布隆过滤器// for (String key : keys) {//     bloomFilter.add(key);// }}@TestString get(String key) {// 3.从布隆过滤器这一级缓存判断key是否存在boolean isContains = bloomFilter.contains(key);if (!isContains) {return "";}// 4.业务逻辑开发}
}

但是布隆过滤器无法删除某一个元素,如果要删除得重新初始化数据

2. 击穿问题

缓存击穿中,请求的 key 对应的是热点数据 ,该数据存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期) 。这就可能会导致瞬时大量的请求直接打到了数据库上,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。
[图片]


解决方案:

  1. 基于互斥锁(看情况):在缓存过期后,通过设置互斥锁确保只有一个请求去查询数据库并且更新缓存。
  2. 提前预热(推荐):针对热点数据提前预热,并将其入缓存中并设置合理的过期事件,比如:秒杀场景下的数据在秒杀结束前永不过期。
  3. 数据永不过期(不推荐):设置热点数据永不过期或者过期时间比较长。

2.1 基于互斥锁解决缓存击穿问题

@Component
public class RedisCacheClient {private final StringRedisTemplate stringRedisTemplate;private final RedissonClient redissonClient;public RedisCacheClient(StringRedisTemplate stringRedisTemplate, RedissonClient redissonClient) {this.stringRedisTemplate = stringRedisTemplate;this.redissonClient = redissonClient;}private void set(String key, Object value, Long time, TimeUnit timeUnit) {stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, timeUnit);}private String get(String key) {return stringRedisTemplate.opsForValue().get(key);}public <ID, R> R query(String keyPrefix, ID id, Class<R> clazz,Function<ID, R> dbFallBack, Long time, TimeUnit unit) {String key = keyPrefix + id;// 1.从redis查询数据String json = get(key);// 2.判断数据是否存在if (RedisConstants.EMPTY_OBJECT_JSON.equals(json)) {return null; //缓存的空对象值}if (StrUtil.isNotEmpty(json)) {return JSONUtil.toBean(json, clazz);}//加锁,防止缓存击穿问题 -> redis的热点key问题RLock redissonClientLock = redissonClient.getLock(RedisConstants.DISTRIBUTED_LOCK + key);redissonClientLock.lock(); //加锁try {//dcl判断锁是否存在了json = get(key);if (json != null) {return queryWithPassThrough(keyPrefix, id, clazz, dbFallBack, time, unit);}//3. 不存在,根据id查询数据库R r = dbFallBack.apply(id);if (r != null) {set(key, r, time, unit);return r;}// 存储空对象set(key, RedisConstants.EMPTY_OBJECT_JSON, RedisConstants.CACHE_NULL_TTL, TimeUnit.SECONDS);return null;} finally {redissonClientLock.unlock();}}
}

3. 雪崩问题

缓存宕机或者在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力。

在这里插入图片描述


解决方式:

  1. 设置随机失效时间(可选):为缓存设置随机的失效时间,例如在固定过期时间的基础上加上一个随机值,这样可以避免大量缓存同时到期,从而减少缓存雪崩的风险。(例如:批量导入数据到redis的时候,如果设置过期时间一致,那么就会数据就会在同一时刻过期删除)。
  2. 多级缓存:设计多级缓存,例如本地缓存+Redis 缓存的二级缓存组合,当 Redis 缓存出现问题时,还可以从本地缓存中获取到部分数据。
  3. Redis集群:采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。比如:Redis Sentinel哨兵集群、Redis Cluster分片集群。
  4. 限流:如果发现读请求太多,可以采用限流的策略。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/32356.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习springboot(Bean 注册,Bean 扫描)

Bean 扫描 可以浏览下面的博客链接 &#xff1a;spring 学习 &#xff08;注解&#xff09;-CSDN博客 在学习spring 注解时&#xff0c;我们使用 Component &#xff0c;Service,Controller等 这样的注解&#xff0c;将目标类信息&#xff0c;传递给IOC容器&#xff0c;为其创…

使用Mermaid语法绘制的C语言程序从Linux移植到Windows的流程图

以下是使用Mermaid语法绘制的C语言程序从Linux移植到Windows的流程图&#xff1a; graph TDA[开始移植] --> B[代码兼容性检查]B --> C[检查系统调用差异\nfork/exec -> CreateProcess]B --> D[检查文件路径格式\n/ vs \\]B --> E[检查依赖库兼容性\nPOSIX vs …

网络信息安全专业(710207)网络安全攻防实训室建设方案

一、引言 随着信息技术的飞速发展&#xff0c;网络空间安全已成为国家安全的重要组成部分&#xff0c;对网络信息安全专业人才的需求日益增长。为满足网络信息安全专业&#xff08;专业代码710207&#xff09;的教学需求&#xff0c;提升学生在网络安全攻防领域的实践能力&…

赶紧白P这款免费神器!

现在&#xff0c;很多视频剪辑软件都开始收费了&#xff0c;真正免费又好用的软件真的越来越难找了。 今天&#xff0c;我给大家推荐一款非常小巧的视频编辑工具&#xff0c;目前完全免费&#xff0c;功能却非常丰富。 咔咔一通剪 视频编辑工具 这款软件真的超级轻巧&#xff…

Qt 初识1.1

目录 QLineEdit QPushButton connet&#xff1a; Qt命名规范 Qt窗口坐标系 QLineEdit ​ ​ QPushButton ​ 给按钮的点击操作上关联一个处理函数。 connet&#xff1a; connet的作用是连接信号和槽&#xff0c;是QObject类中的一个静态函数&#xff0c; ​ Qt命…

Linux内核机制之epoll详解

目录 简介&#xff1a; 一、IO 多路复用介绍 1、select&#xff0c;poll&#xff0c;epoll 引入 2、select&#xff0c;poll&#xff0c;epoll 区别分析 3、epoll 原理 3.1 epoll 相关函数介绍 1&#xff09;epoll_create 2&#xff09;epoll_ctl 3&#xff09;epoll_…

以 ArcGIS Pro 为笔,绘就水墨地图画卷

一、引言 水墨画&#xff0c;作为中国传统绘画艺术的瑰宝&#xff0c;以其独特的韵味和表现力&#xff0c;在艺术领域占据着重要地位。它通过水与墨的交融&#xff0c;展现出山水之间的灵动与韵味。 而将这种艺术形式与现代地理信息系统&#xff08;GIS&#xff09;技术相结合…

JAVA:利用 Jsoup 轻松解析和操作 HTML 的技术指南

1、简述 在现代 Java 开发中&#xff0c;处理 HTML 数据是一项常见需求&#xff0c;无论是抓取网页数据、解析 HTML 文档&#xff0c;还是操作 DOM 树&#xff0c;Jsoup 都是一个强大的工具。它是一个基于 Java 的 HTML 解析库&#xff0c;支持从 URL、文件或字符串中解析 HTM…

个人记录的一个插件,Unity-RuntimeMonitor

没有什么干货,仅仅是个人的记录 基于GUI做的一个工具:好处就是Monitor必须,Unity天然支持实时的Monitor;唯一不好处,就是默认字体太小了,layout居中,居右也是要自行设计的。 (下面文字是有一点点写错,但意思和功能就很牛逼了;并不是都按2 x shift,而是一个 shift 添…

云服务器安装宝塔面板部署

单机部署(前端vue项目) 服务器安装宝塔面板 连接到服务器 使用 SSH 连接到你的服务器&#xff1a; ssh rootip安装宝塔面板 运行以下命令来安装宝塔面板&#xff1a; yum install -y wget wget -O install.sh http://download.bt.cn/install/install_6.0.sh sh install.sh安…

Java数据结构第二十期:解构排序算法的艺术与科学(二)

专栏&#xff1a;Java数据结构秘籍 个人主页&#xff1a;手握风云 目录 一、常见排序算法的实现 1.1. 直接选择排序 1.2. 堆排序 1.3. 冒泡排序 1.4. 快速排序 一、常见排序算法的实现 1.1. 直接选择排序 每⼀次从待排序的数据元素中选出最小的⼀个元素&#xff0c;存放在…

【MapSet】哈希表

目录 1. 搜索树 1.1 概念 1.2 操作-查找 1.3 操作-插入 1.4 操作-删除&#xff08;难点&#xff09; 1.5 性能分析 1.6 和java类集的关系 2. 搜索 2.1 概念及场景 2.2 模型 3. Map的使用 3.1 关于Map的说明 3.2 关于Map.Entry的说明 3.3 Map的常用方法说明 3.4 …

手写一个Tomcat

Tomcat 是一个广泛使用的开源 Java Servlet 容器&#xff0c;用于运行 Java Web 应用程序。虽然 Tomcat 本身功能强大且复杂&#xff0c;但通过手写一个简易版的 Tomcat&#xff0c;我们可以更好地理解其核心工作原理。本文将带你一步步实现一个简易版的 Tomcat&#xff0c;并深…

git commit messege 模板设置 (规范化管理git)

配置方法 git config --global core.editor vim &#xff08;设置 Git 的默认编辑器为 Vim&#xff09;在用户根目录下&#xff08;~&#xff09;&#xff0c;创建一个.git_commit_msg文件&#xff0c;然后把下面的内容拷贝到文件中并保存。 [version][模块][类型]{解决xxx问题…

亚信安全发布第七期《勒索家族和勒索事件监控报告》

本周态势快速感知 本周全球共监测到勒索事件121起&#xff0c;与上周相比&#xff0c;勒索事件数量大幅下降&#xff0c;仍需注意防范。从整体上看Clop是影响最严重的勒索家族&#xff1b;本周Ransomhub和Akira也是活动频繁的两个恶意家族&#xff0c;需要注意防范。本周&…

React基础之项目实战

规范的项目结构 安装scss npm install sass -D 安装Ant Design组件库 内置了一些常用的组件 npm install antd --save 路由基础配置 npm i react-router-dom 路由基本入口 import Layout from "../page/Layout"; import Login from "../page/Login"; impor…

第44天:WEB攻防-PHP应用SQL盲注布尔回显延时判断报错处理增删改查方式

时间轴&#xff1a; 44天知识点总结&#xff1a; 1.mysql的增删改查功能 2.根据源码sql语句的三种sql注入&#xff1a;布尔盲注&#xff08;必须要有回显&#xff09; 延时判断&#xff08;都可以&#xff09; 报错回显&#xff08;必须要有报错处理机制&#xff09; 3.两个cms…

【51单片机】程序实验15.DS18B20温度传感器

主要参考学习资料&#xff1a;B站【普中官方】51单片机手把手教学视频 开发资料下载链接&#xff1a;http://www.prechin.cn/gongsixinwen/208.html 单片机套装&#xff1a;普中STC51单片机开发板A4标准版套餐7 目录 DS18B20介绍主要特性内部结构控制时序初始化时序写时序读时序…

Vue3 深度解析:构建现代Web应用的全新范式

Vue3 深度解析&#xff1a;构建现代Web应用的全新范式 mindmaproot(Vue3核心革新)性能优化Proxy响应式编译优化体积缩减Composition APIsetup语法逻辑复用TypeScript支持新特性TeleportSuspense片段支持工程化Vite集成自定义渲染器服务端渲染一、Vue3 架构革新&#xff1a;从O…

推理模型对SQL理解能力的评测:DeepSeek r1、GPT-4o、Kimi k1.5和Claude 3.7 Sonnet

引言 随着大型语言模型&#xff08;LLMs&#xff09;在技术领域的应用日益广泛&#xff0c;评估这些模型在特定技术任务上的能力变得越来越重要。本研究聚焦于四款领先的推理模型——DeepSeek r1、GPT-4o、Kimi k1.5和Claude 3.7 Sonnet在SQL理解与分析方面的能力&#xff0c;…