缓存穿透,缓存击穿,缓存雪崩

目录

介绍

缓存穿透

缓存击穿

缓存雪崩

原因

影响

解决方案

缓存穿透

防止缓存穿透->空值缓存案例

缓存击穿

使用互斥锁解决缓存击穿


                                                    介绍

   缓存穿透

定义:缓存穿透是指用户查询数据,缓存和数据库中都不存在该数据(一般是发起恶意的查询,试图击穿缓存,直接查询数据库),这时用户每次查询都会直接打到数据库上,而数据库中也没有该数据,如果用户不断发起这样的请求,数据库压力会非常大,甚至可能拖垮数据库。

解决方案

  1. 布隆过滤器(Bloom Filter):布隆过滤器可以快速判断一个元素是否在一个集合中,但是会有一定的误判率。在数据放入缓存之前,先使用布隆过滤器判断数据是否存在,如果不存在则直接返回,不进行数据库查询。
  2. 空值缓存:对于不存在的数据,也在缓存中存放一个空值(或者一个特殊标记),这样下次查询相同的数据时,可以直接返回缓存中的空值,避免了对数据库的查询。但是这种方法需要设置合理的过期时间,避免数据长时间不更新。
  3. 请求限流:对查询请求进行限流,限制查询频率,防止恶意查询。

   缓存击穿

定义:缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

解决方案

  1. 设置热点数据永不过期,即逻辑缓存:对于一些热点数据,可以将其设置为永不过期,从而避免缓存击穿问题。但是这种方法会占用较多的缓存空间,需要谨慎使用。
  2. 加互斥锁:在查询数据库之前,先尝试获取一个分布式锁,如果获取到锁,则查询数据库并更新缓存;如果未获取到锁,则等待一段时间后重试。这样可以保证同一时间只有一个请求去查询数据库,从而减轻数据库压力。
  3. 双缓存策略:使用两个缓存,一个缓存的过期时间较短,用于应对大部分请求;另一个缓存的过期时间较长,用于应对缓存击穿的情况。当短缓存过期时,先从长缓存中获取数据,然后再去查询数据库并更新两个缓存。

   缓存雪崩

缓存雪崩是指在缓存中存储的大量数据同时失效或过期,导致缓存系统无法承载大量请求压力,造成服务宕机甚至瘫痪的情况。这种情况下,大量的请求会直接涌入数据库,导致数据库崩溃或响应缓慢,影响应用程序的正常使用。

原因

缓存雪崩通常由于以下几个原因引起:

  1. 缓存过期策略:如果大量的缓存数据被设置为相同的过期时间,那么在这些数据同时过期时,就会引发缓存雪崩。
  2. 缓存服务器故障:当缓存服务器(如Redis)宕机或网络中断时,缓存服务将不可用,所有请求都会直接打到数据库上。
  3. 大量突发请求:在特定时间段内,如果请求量激增且超出缓存系统的处理能力,也可能导致缓存雪崩。

 影响

缓存雪崩的影响是灾难性的,主要包括以下几个方面:

  1. 数据库负载过高:大量的请求直接打到数据库上,导致数据库负载急剧增加,响应时间延长。
  2. 服务不可用:在极端情况下,数据库可能因为压力过大而崩溃,导致整个服务不可用。
  3. 性能瓶颈:数据库成为瓶颈,系统整体处理能力下降,用户体验受到严重影响。
  4. 连锁反应:由于服务间的依赖关系,缓存雪崩可能导致多个服务相继瘫痪,形成连锁反应。

 解决方案

为了防范和应对缓存雪崩,可以采取以下策略:

  1. 设置随机过期时间:为不同的缓存数据设置随机的过期时间,避免大量数据同时过期。
  2. 限流和熔断:当检测到缓存系统压力过大时,通过限流组件限制请求量,并在必要时采取熔断措施,如返回默认数据或静态页面。
  3. 主动更新缓存:在缓存失效前,主动提前重新加载数据至缓存,以减轻数据库压力。
  4. 加锁机制:当缓存失效后,通过加锁机制控制只有一个线程负责从数据库加载数据并回填缓存,其他线程等待或返回旧数据。
  5. 部署缓存集群:部署Redis Sentinel或Cluster集群等缓存集群方案,确保单点故障时能自动切换到其他节点。
  6. 使用布隆过滤器:在缓存之前使用布隆过滤器判断请求的键是否存在,减少对数据库的无效访问。

                                         缓存穿透

缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。给数据库带来巨大压力

常见的解决方案有两种:

缓存空对象

  • 优点:实现简单,维护方便
  • 缺点:额外的内存消耗    可能造成短期的不一致

布隆过滤

优点:内存占用较少,没有多余key

缺点:实现复杂      存在误判可能

还有的解决方案:主动性的方案

  • 增强id的复杂性,避免被猜测id规律
  • 做好数据的基础格式校验
  • 加强用户权限校验
  • 做好热点参数的限流

  防止缓存穿透->空值缓存案例

public Shop queryWithPassThrough(Long id) {String key = CACHE_SHOP_KEY + id;Map<Object, Object> shopFromCache = stringRedisTemplate.opsForHash().entries(key);System.out.println("Redis: " + shopFromCache);// 检查 Redis 返回的 shopFromCache 是否为 nullif (shopFromCache != null && !shopFromCache.isEmpty()) {// 缓存中有值,尝试反序列化 Shop 对象Shop shopFromCacheBean = BeanUtil.fillBeanWithMap(shopFromCache, new Shop(), false);return shopFromCacheBean;}// Redis 中不存在,从数据库中查询Shop shopFromDb = baseMapper.selectById(id);// 数据库中也不存在,则缓存空值以防缓存穿透if (ObjectUtil.isNull(shopFromDb)) {stringRedisTemplate.opsForHash().put(key, CACHE_SHOP_EMPTY_KEY, CACHE_SHOP_EMPTY_VALUE); // 使用特殊标记表示空值stringRedisTemplate.expire(key, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);return null;}// 将 Shop 对象转换为 Map 并写入 RedisMap<String, Object> shopMap = BeanUtil.beanToMap(shopFromDb, new HashMap<>(),CopyOptions.create().ignoreNullValue().setFieldValueEditor((fieldName, fieldValue) -> fieldValue != null ? fieldValue.toString() : null));stringRedisTemplate.opsForHash().putAll(key, shopMap);// 设置超时时间stringRedisTemplate.expire(key, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);return shopFromDb;
}

                 缓存击穿                       

缓存击穿问题也叫热点key问题,就是一个被高并发访问并且缓存重建业务复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击

解决方案 优点 缺点

互斥锁 没有额外的内存消耗 线程需要等待,性能受影响

保证一致性 可能有死锁风险

实现简单

逻辑过期 线程无需等待,性能较好 不保证一致性

有额外内存消耗

实现复杂

使用互斥锁解决缓存击穿

@Overridepublic Result queryById(Long id) throws InterruptedException {// 缓存穿透
//            queryWithPassThrough(id);// 互斥锁解决缓存击穿Shop shop = queryWithMutex(id);if (shop==null) {return Result.fail("商品不存在");}return Result.ok(shop);}public Shop queryWithMutex(Long id) throws InterruptedException {String key = CACHE_SHOP_KEY + id;Map<Object, Object> shopFromCache = stringRedisTemplate.opsForHash().entries(key);System.out.println("Redis: " + shopFromCache);// 检查 Redis 返回的 shopFromCache 是否为 nullif (shopFromCache != null && !shopFromCache.isEmpty()) {// 缓存中有值,尝试反序列化 Shop 对象Shop shopFromCacheBean = BeanUtil.fillBeanWithMap(shopFromCache, new Shop(), false);return shopFromCacheBean;}// Redis 中不存在,从数据库中查询// 4.实现缓存重建// 4.1获取互斥锁// 4.2获取失败,休眠然后重试// 4.3获取成功,返回数据,释放锁Shop shopFromDb=null;try {boolean isLock = tryLock(LOCK_SHOP_KEY + id);if (!isLock) {// 拿不到锁,休眠,然后递归不断尝试// 这个返回结果会是在redis里拿到的数据Thread.sleep(50);return queryWithMutex(id);}// 拿到互斥锁,查询数据库,重建缓存shopFromDb= baseMapper.selectById(id);
//            模拟重建延迟Thread.sleep(200);// 数据库中也不存在,则缓存空值以防缓存穿透stringRedisTemplate.opsForHash().put(key, CACHE_SHOP_EMPTY_KEY, CACHE_SHOP_EMPTY_VALUE); // 使用特殊标记表示空值stringRedisTemplate.expire(key, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);return null;}// 将 Shop 对象转换为 Map 并写入 RedisMap<String, Object> shopMap = BeanUtil.beanToMap(shopFromDb, new HashMap<>(),CopyOptions.create().ignoreNullValue().setFieldValueEditor((fieldName, fieldValue) -> fieldValue != null ? fieldValue.toString() : null));stringRedisTemplate.opsForHash().putAll(key, shopMap);// 设置超时时间stringRedisTemplate.expire(key, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e) {throw new RuntimeException(e);} finally {// 释放锁unLock(LOCK_SHOP_KEY + id);}return shopFromDb;}
public   boolean tryLock(String key) {Boolean b = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(b);
}public   void unLock(String key) {stringRedisTemplate.delete(key);
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Mac应用快速启动器:Alfred 5 for Mac 激活版

Alfred 5 是一款专为 macOS 系统设计的效率提升工具。这款软件以其快速启动和高效操作功能著称&#xff0c;通过使用快捷键来呼出输入界面&#xff0c;用户可以快速完成各种任务。 最新版本 Alfred 5.5 引入了一些新功能。其中包括整合了 ChatGPT 和 DALL-E&#xff0c;这意味…

linux root登陆,密码正确但,错误提示su: Authentication failure

初开始登陆的时候会显示失败&#xff0c;参考了很多网上的做法&#xff0c;但还是不行&#xff0c;但是&#xff0c;如果用键盘左边那一排数字按键输入&#xff0c;就可以正常登陆&#xff08;之前用的是右边的九宫格&#xff09;

Mindspore框架循环神经网络RNN模型实现情感分类|(四)损失函数与优化器

Mindspore框架循环神经网络RNN模型实现情感分类 Mindspore框架循环神经网络RNN模型实现情感分类|&#xff08;一&#xff09;IMDB影评数据集准备 Mindspore框架循环神经网络RNN模型实现情感分类|&#xff08;二&#xff09;预训练词向量 Mindspore框架循环神经网络RNN模型实现…

图论之求树的重心

文章目录 题目简要分析解题思路代码实现 题目 原题链接&#xff1a;https://www.acwing.com/problem/content/848/ 题目描述 给定一颗树&#xff0c;树中包含 n 个结点&#xff08;编号 1∼n&#xff09;和 n−1条无向边。请你找到树的重心&#xff0c;并输出将重心删除后&am…

钉钉 ai卡片 stream模式联调

sdk连接 新建卡片模板下载node.js sdkconfig.json 配置应用信息 启动项目npm i npm run build npm run start连接成功 获取卡片回调 注册卡片回调事件调用https://api.dingtalk.com/v1.0/card/instances 创建卡片实例&#xff0c;返回实例Id //参数结构 {"cardTempla…

Linux文件与相关函数的知识点1

Open函数 高频使用的Linux系统调用&#xff1a;open write read close Linux 自带的工具&#xff1a;man手册&#xff1a; man 1是普通的shell命令&#xff0c;比如ls 调用命令&#xff1a;man 1 ls man 2是系统调用函数&#xff0c;比如open&#xff0c;write 调用open…

AV1技术学习:Quantization

量化是对变换系数进行&#xff0c;并将量化索引熵编码。AV1的量化参数 QP 的取值范围是0 ~ 255。 一、Quantization Step Size 在给定的 QP 下&#xff0c;DC 系数的量化步长小于 AC 系数的量化步长。DC 系数和 AC 系数从 QP 到量化步长的映射如下图所示。当 QP 为 0 时&…

MySQL的高可用(MHA)

高可用模式下的故障切换&#xff0c;基于主从复制。 单点故障和主从复制不能切换的问题。 至少需要三台。 故障切换过程0-30秒 vip地址&#xff0c;根据vip地址所在的主机&#xff0c;确定主备。 主 vip 备 vip 主和备不是优先级确定的&#xff0c;主从复制的时候就确定…

BGP之选路MED

原理概述 当一台BGP路由器中存在多条去往同一目标网络的BGP路由时&#xff0c;BGP协议会对这些BGP路由的属性进行比较&#xff0c;以确定去往该目标网络的最优BGP路由。BGP路由属性的比较顺序为Preferred Value属性、Local Preference属性、路由生成方式、AS_Path属性、Origin属…

一款简而轻的项目运维监控软件,支持低侵入式在线构建、自动部署、日常运维(附源码)

前言 在当今快速发展的软件开发领域&#xff0c;开发团队经常面临一系列运维挑战。没有专业运维人员的支持&#xff0c;开发人员不得不承担构建和部署项目的任务。 面对不同项目的构建和部署命令&#xff0c;以及多环境的打包需求&#xff0c;开发人员需要一个能够简化这些流…

算法 day4 【双指针、快慢指针、环形链表】链表下

⚡刷题计划day4继续&#xff0c;可以点个免费的赞哦~ 下一期将会开启哈希表刷题专题&#xff0c;往期可看专栏&#xff0c;关注不迷路&#xff0c; 您的支持是我的最大动力&#x1f339;~ 目录 ⚡刷题计划day4继续&#xff0c;可以点个免费的赞哦~ 下一期将会开启哈希表刷题…

C# 匿名函数与Lambda表达式

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 1.匿名函数 在 C# 中&#xff0c;匿名函数是一种没有名称的函数&#xff0c;可以直接在代码中定义和使用 匿名函数主要有两种形式&#xff1a;匿名方法和Lambda 表…

Modbus转EtherCAT网关将Modbus协议的数据格式转换为EtherCAT协议

随着工业自动化技术的快速发展&#xff0c;不同通信协议之间的互操作性变得越来越重要。Modbus作为一种广泛使用的串行通信协议&#xff0c;与以太网为基础的EtherCAT协议之间的转换需求日益增长。本文将从网关功能、硬件设计、性能以及应用案例来介绍这款Modbus转EtherCAT网关…

TinaLinux ssh 环境搭建

adb shell passwd root #修改密码 vim /etc/ssh/sshd_config #编辑SSH配置文件/etc/ssh/sshd_config&#xff0c;根据需要配置如端口、允许登录的用户等 切换为英文输入法输入i&#xff0c;将下面PermitRootLogin和PasswordAuthentication改成yes PermitRootLogin yes…

华媒舍:6个媒体宣发套餐,快速突破传播界限

在当今信息爆炸的社会中&#xff0c;有效地传播自己的信息变得愈发困难。特别是对于媒体宣发来说&#xff0c;如何在市场竞争激烈的情况下突破传播界限&#xff0c;让自己的消息传达给更多的人&#xff0c;这是每个企业和个人都面临的难题。 为了解决这个问题&#xff0c;我们推…

MSPM0GXX单片机内部比较器深度解析

目录 0 前言1 简介1.1单片机简介1.2 比较器简介 2 比较器运行原理2.1 比较器配置2.2 比较器通道选择2.3 比较器输出2.4 输出滤波器2.5 采样输出模式2.6 消隐模式2.7 基准电压发生器2.8 窗口比较器模式2.9 比较器滞后 3 比较器的优势 0 前言 本文仅以TI公司生产的MSPM0GXX单片机…

【BUG】已解决:You are using pip version 10.0.1, however version 21.3.1 is available.

You are using pip version 10.0.1, however version 21.3.1 is available. 目录 You are using pip version 10.0.1, however version 21.3.1 is available. 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#…

【Django】 读取excel文件并在前端以网页形式显示-安装使用Pandas

文章目录 安装pandas写views写urls安装openpyxl重新调试 安装pandas Pandas是一个基于NumPy的Python数据分析库&#xff0c;可以从各种文件格式如CSV、JSON、SQL、Excel等导入数据&#xff0c;并支持多种数据运算操作&#xff0c;如归并、再成形、选择等。 更换pip源 pip co…

Word 导入导出

在实际的开发过程中&#xff0c;也会遇到导入导出的功能&#xff0c;今天就简单的做一下总结。 1.需求&#xff1a;将下面word 数据导入到数据库并进行存储 在Controller中 RequestMapping(value "/ImportWord")public RawResponseBodyObject ImportWord(HttpServl…

VBA技术资料MF178:将某个文件夹中的图片导入Word

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…