【Redis】缓存三大问题与缓存一致性问题

缓存三大问题

缓存穿透

缓存穿透是指用户查询的数据在缓存和数据库中都不存在,导致每次请求都会直接落到数据库上,增加数据库负载。

解决方案

1)参数校验

一些不合法的参数请求直接抛出异常信息返回给客户端。比如查询的数据库 id 不能小于 0、传入的邮箱格式不对的时候直接返回错误消息给客户端等等。

2)缓存无效 key

如果缓存和数据库都查不到某个 key 的数据就写一个到 Redis 中去并设置过期时间,具体命令如下:SET key value EX 10086这种方式仅能解决请求的 key 变化不频繁的情况

3)布隆过滤器

把所有可能存在的请求的值都存放在布隆过滤器中,当用户请求过来,先判断用户发来的请求的值是否存在于布隆过滤器中。不存在的话,直接返回请求参数错误信息给客户端,存在的话才会走下面的流程。

4)接口限流

根据用户或者 IP 对接口进行限流,对于异常频繁的访问行为,还可以采取黑名单机制,例如将异常 IP 列入黑名单。

缓存击穿

缓存击穿是指热点数据在缓存过期后,大量请求同时查询该数据,导致请求直接落到数据库上,瞬间对数据库造成巨大压力。

解决方案

  1. 针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。

  2. 查询缓存过期后,先获取互斥锁,然后再将数据库中的数据写入到缓存中,保证只有一个请求会落到数据库上,减少数据库的压力。

  3. 缓存中添加一个逻辑过期字段,如果查询到缓存过期,先获取互斥锁,然后开启一个新线程重构缓存过期时间,其他线程如果获取互斥锁失败,直接返回过期数据,从而减少到达数据库的请求。

缓存雪崩

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

解决方案

1)针对 Redis 服务不可用的情况:

  1. 集群部署: 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
  2. 限流与降级:对请求进行限流,防止大量请求同时落到数据库上。同时,在缓存不可用时,可以返回默认值或进行降级处理。
  3. 使用多级缓存架构:结合本地缓存和分布式缓存,减少对分布式缓存的直接依赖。在缓存失效时,首先查询本地缓存,如果没有,再查询分布式缓存。

2)针对热点缓存失效的情况:

  1. 设置随机的过期时间,在设定的基础上添加一个随机值,避免大量缓存同时失效。
  2. 缓存永不失效(不太推荐,实用性太差)。
  3. 缓存预热,在系统启动或者缓存失效前,通过后台任务将常用的数据加载到缓存中,防止缓存刚启动时产生大量数据库请求。

实现缓存预热

常见的缓存预热方式有两种:

  1. 使用定时任务,比如 xxl-job,来定时触发缓存预热的逻辑,将数据库中的热点数据查询出来并存入缓存中。
  2. 使用消息队列,比如 Kafka,来异步地进行缓存预热,将数据库中的热点数据的主键或者 ID 发送到消息队列中,然后由缓存服务消费消息队列中的数据,根据主键或者 ID 查询数据库并更新缓存。

数据一致性问题

什么情况下会出现数据一致性问题?

因为缓存的操作和数据库的操作是存在一定的时间差的。而且这两个操作是没办法保证原子性的,也就是说,是有可能一个操作成功,一个操作失败的。所以,这就必然会存在不一致的情况。

写写并发问题

先写数据库,再写缓存的情况。

WW
写数据库,更新成20
写数据库,更新成10
写缓存,更新成10
写缓存,更新成20**(数据不一致)**

先写缓存,再写数据库的情况。

WW
写缓存,更新成20
写缓存,更新成10
写数据库,更新成10
写数据库,更新成20**(数据不一致)**

读写并发问题

WR
读缓存,缓存中没有数据
读数据库,数据库中数据为10
写数据库,更新成20
写缓存,更新成10**(数据不一致)**

如何解决数据一致性问题

1.删除缓存还是更新缓存

  • 更新缓存更加复杂: 在缓存中,当数据不仅仅是简单的字符串(如JSON串或map类型),更新缓存变得更为复杂和易出错。例如,扣减库存时,需要从缓存中取出整个订单模型,反序列化后修改库存字段,再序列化并更新回缓存。相比之下,直接删除缓存再重建的策略更为简洁。
  • 更新缓存更容易出现数据不一致: 在“写写并发”的场景中,如果同时更新缓存和数据库,很容易会出现因为并发的问题导致数据不一致的情况。但是,如果是做缓存的删除的话,在写写并发的情况下,缓存中的数据都是要被清除的,所以就不会出现数据不一致的问题。
  • 删除缓存会出现Cache miss问题: 在删除缓存后的下一次查询会无法命中缓存,要查询一下数据库。这种cache miss在某种程度上可能会导致缓存击穿,也就是刚好缓存被删除之后,同一个Key有大量的请求过来,导致缓存被击穿,大量请求访问到数据库。但是,通过加锁的方式是可以比较方便的解决缓存击穿的问题的。

2.先删缓存还是先更新数据库(推荐先更新数据库)

  • 先删缓存

好处: 缓存删除之后,就不存在数据不一致的问题了。

坏处: 由于读写并发问题(当缓存不存在数据时,读线程读取数据库后需要写入缓存),先删缓存刚好可以让读线程读不到缓存,会加大这种可能性的发生。此外,缓存被删除后,更容易出现缓存击穿的问题。(此处引出缓存三大问题)

  • 先更新数据库

好处: 缓存删除失败的概率比较低,除非是网络问题或者缓存服务器宕机。先更新数据库,确保数据是最新的,即使缓存删除失败,数据出现短暂的不一致,在下次查询缓存时如果缓存过期,就会更新缓存,使得数据一致。(此处引出延迟双删,因为如果第一次缓存删除失败了,下一次查询时缓存没过期,就会查询到旧数据导致数据不一致)

坏处: 由于整个过程不是一个原子操作。一旦删除缓存失败,就会导致数据库中的数据已经更新,但是缓存还是旧数据,产生数据不一致。

延迟双删策略

@service
public class Productservice {@Autowiredprivate stringRedisTemplate redisTemplate;// 定义阻塞队列private final BlockingQueuexstring> cacheDeletionQueue = new LinkedBlockingQueue<>();public void updateProduct(Product product) {//第一次删除缓存deletecache(product.getId());// 更新数据库updateProductInDB(product);// 第二次删除缓存,将缓存key存入阻塞队列cacheDeletionQueue.add(product.getId());}// 时间到后,从阻塞队列中取出key,删除缓存@scheduled(fixedDelay =100)public void delayedcacheDeletion(){String productId = cacheDeletionQueue.poll();if(productId != null) {deletecache(productId);	//删除缓存}  }
}

为什么是删除缓存-->更新数据库-->删除缓存这个顺序?

  1. 防止读取到旧缓存数据
    • 先更新数据库,再删除缓存:假设先更新数据库再删除缓存,在删除缓存之前,可能有其他并发请求读取到旧的缓存数据。这些请求可能会在删除缓存之后将旧数据重新写入缓存,从而导致数据不一致。
    • 先删除缓存,再更新数据库:通过在更新数据库之前删除缓存,可以确保即使有并发请求,它们也会读取数据库的最新数据(因为缓存已被删除),从而写入新的缓存数据。
  2. 处理并发请求带来的数据不一致
    • 不做处理:在更新数据库之前,可能有其他并发请求读取了旧的数据库数据。这些请求可能会在更新数据库之后重新写入缓存,从而导致数据不一致。
    • 延迟删除缓存:延迟一段时间后再次删除缓存,确保缓存中不会存有旧数据。
      写入新的缓存数据。
  3. 处理并发请求带来的数据不一致
    • 不做处理:在更新数据库之前,可能有其他并发请求读取了旧的数据库数据。这些请求可能会在更新数据库之后重新写入缓存,从而导致数据不一致。
    • 延迟删除缓存:延迟一段时间后再次删除缓存,确保缓存中不会存有旧数据。

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

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

相关文章

python3.10安装geopandans实战笔记

1.geopandans安装所需软件库版本 python3.10 GDAL-3.4.3-cp310-cp310-win_amd64.whl【手动下载】 Fiona-1.8.21-cp310-cp310-win_amd64.whl【手动下载】 shapely-2.0.2-cp310-cp310-win_amd64.whl【手动下载】 pyproj 手动下载地址&#xff1a;https://download.csdn.net/down…

Unity入门5——材质

创建材质 点击Assets → Create → Material&#xff0c;得到一个默认材质球的副本。 使用材质 直接把材质球拖拽到物体上&#xff0c;或设置mesh renderer组件下的Materials 数组中第一个元素

html+css网页设计公司网站模版3个页面 无js 静态页面

htmlcss网页设计公司网站模版3个页面 无js 静态页面 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源…

iOS弱引用

背景&#xff1a;在面试过程中被问到如果两个对象已经发生循环引用了&#xff0c;该如何将他们剪断&#xff0c;在运行态的时候。 由于这个场景比较抽象&#xff0c;我理解面试官是希望我通过运行时的方法和方式来解决循环引用。 解决方案一: 重写setter用关联对象来实现wea…

数据库规范化设计 5大基本原则

规范化设计原则是数据库设计的基本原则&#xff0c;有助于减少数据冗余&#xff0c;提高数据一致性和完整性&#xff0c;简化数据管理&#xff0c;增强数据安全性&#xff0c;对整个开发项目至关重要。而缺乏规范化设计会导致数据冗余&#xff0c;增加存储成本&#xff0c;引发…

java 如何查看jar版本冲突,如何查看哪个模块依赖冲突,idea查看jar包冲突

1. idea 下载插件&#xff1a; 2. 如上图所示&#xff0c;下载Maven Helper, 注意是maven helper 不是别的 3.重启idea 4.点击pom文件&#xff0c;然后点击如图所示&#xff1a; 5. 如此即可查到&#xff0c;某个jar包 都有哪个模块依赖&#xff0c;使用的什么版本&#xff0…

【JavaEE】定时器

目录 前言 什么是定时器 如何使用java中的定时器 实现计时器 实现MyTimeTask类 Time类中存储任务的数据结构 实现Timer中的schedule方法 实现MyTimer中的构造方法 处理构造方法中出现的线程安全问题 完整代码 考虑在限时等待wait中能否用sleep替换 能否用PriorityBlo…

RISC-V竞赛|第二届 RISC-V 软件移植及优化锦标赛报名正式开始!

目录 赛事背景 赛道方向 适配夺旗赛 优化竞速赛 比赛赛题&#xff08;总奖金池8万元&#xff01;&#xff09; &#x1f525;竞速赛 - OceanBase 移植与优化 比赛赛程&#xff08;暂定&#xff09; 赛事说明 「赛事背景」 为了推动 RISC-V 软件生态更快地发展&#xff0…

收银系统源码-连锁店版本

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 私有化独立部署/全开源源码&#xff0c;系统开发语言&#xff1a; 核心开发语言: PHP、HTML…

【vue3】【elementPlus】【黑暗模式】

从创建vue3项目到引入elementPlus组件并设置黑暗模式 1.创建vue3项目&#xff1a; npm init vuelatest1.1 根据需求定制项目插件&#xff1a; 2.引入elementPlus组件&#xff1a; npm install element-plus --save2.1 如图注册全局elementPlus组件&#xff1a; ------------…

SPSS、Python员工满意度问卷调查激励保健理论研究:决策树、随机森林和AdaBoost|附代码数据

全文链接&#xff1a;https://tecdat.cn/?p37293 原文出处&#xff1a;拓端数据部落公众号 在深入了解公司当前的实际情况和员工内心真实想法的基础上&#xff0c;我们旨在从专业视角出发&#xff0c;为企业在组织管理方面的不足进行诊断&#xff0c;并进行全面审视。 为了…

vue实现PC端图片放大缩小可鼠标拖动,鼠标滚轮控制放大缩小完整代码付效果图

vue实现图片放大缩小可鼠标拖动&#xff0c;鼠标滚轮控制放大缩小完整代码付效果图 效果图&#xff1a; 创建一个ImageViewer 组件&#xff0c;并且在当前页面引用完整代码如下&#xff1a; 代码引用&#xff1a; <template><view><image-viewer :imageUrl&q…

2024年必备技能:智联招聘岗位信息采集技巧全解析

随着大数据时代的发展&#xff0c;精准定位职业机会成为程序员求职的关键。本文将深入解析如何利用Python高效采集智联招聘上的岗位信息&#xff0c;助你在2024年的职场竞争中脱颖而出。通过实战代码示例&#xff0c;揭示网络爬虫背后的秘密&#xff0c;让你轻松掌握这一必备技…

苹果应用程序清理卸载工具:App Cleaner Uninstaller Pro for Mac

App Cleaner & Uninstaller Pro 是一款专为 Mac OS X 操作系统设计的应用程序清理和卸载工具。这款软件的主要功能是帮助用户彻底删除不需要的应用程序、插件和残留文件&#xff0c;从而释放磁盘空间并提高系统性能。 特点和优势&#xff1a; 彻底卸载应用程序&#xff1a;…

历代文学-技术生态-总体介绍

1. 历代文学简介 历代文学&#xff08;https://literature.sinhy.com/#/literature?__c1000&#xff0c;微信小程序可直接搜索“历代文学”&#xff09;是一个由两个人&#xff08;一个后端和一个前端&#xff09;开发的文学网站&#xff0c;是一个收录从古到今、以及古今中外…

几款设计师必备的AI抠图软件工具分享给你!

前言 在图像处理领域&#xff0c;抠图是一项基本而关键的技能。传统上&#xff0c;PS是作为抠图的首选工具&#xff0c;但其操作复杂性往往令初学者望而却步。幸运的是&#xff0c;随着AIGC技术的发展&#xff0c;现在有多款AI软件和在线网站能够以更简单、快捷的方式完成抠图…

VS+Qt+C++点云PCL三维显示编辑系统

程序示例精选 VSQtC点云PCL三维显示编辑系统 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《VSQtC点云PCL三维显示编辑系统》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易…

【wiki知识库】08.添加用户登录功能--后端SpringBoot部分

目录 一、今日目标 二、SpringBoot后端实现 2.1 新增UserLoginParam 2.2 修改UserController 2.3 UserServiceImpl代码 2.4 创建用户上下文工具类 2.5 通过token校验用户&#xff08;重要&#xff09; 2.6 创建WebMvcConfig 2.7 用户权限校验拦截器 一、今日目标 上篇…

【大模型】大模型指令微调的“Prompt”模板

文章目录 一、微调数据集格式二、常用的指令监督微调模板2.1 指令跟随格式&#xff08;Alpaca&#xff09;2.2 多轮对话格式&#xff08;ShareGPT&#xff09;2.3 其他形式2.4 常见模板 参考资料 一、微调数据集格式 在进行大模型微调的过程中&#xff0c;我们会发现“Prompt”…

mysql 日志爆满,删除日志文件,定时清理日志

今天发现网站不能正常访问&#xff0c;于是登陆服务器查找问题。 机智的我随手用命令&#xff1a;df -l 发现 硬盘爆满了&#xff0c;于是就知道问题所在了。 Filesystem 1K-blocks Used Available Use% Mounted on/dev/xvda1 20641404 16963004 16929876 10…