如何保证MySQL和Redis中的数据一致性?

news2024/11/15 11:47:33

文章目录

  • 前言
  • 一、缓存案例
    • 1.1 缓存常见用法
    • 1.2 缓存不一致产生的原因
  • 二、解决方案
    • 2.1 先删除缓存,再更新数据库
    • 2.2 先更新数据库,删除缓存
    • 2.3 只更新缓存,由缓存自己同步更新数据库
    • 2.4 只更新缓存,由缓存自己异步更新数据库
    • 2.5 引入 MQ
  • 三、总结

前言

在高并发的场景下,大量的请求直接访问MySQL很容易造成性能瓶颈。所以,我们都会用Redis来做数据的缓存,削减对数据库的压力。但是,MySQL和Redis是两种不同的数据库,如何保证不同数据库之间数据的一致性就非常关键了。

关于MySQL和Redis中的数据一致性问题,可以先说一下结论:没有完美的方案,只有最适合某场景的方案。这个问题表面上看是数据一致性的问题,其实根本上,又是数据一致性、系统性能和系统复杂度的选择与取舍。我们所能做到的是尽可能让它们的数据在绝大部分时间内保持一致,并保证最终是一致的。

一、缓存案例

1.1 缓存常见用法

通常情况下,我们使用缓存的主要目的是为了提升查询的性能。大多数情况下,我们使用缓存的例子如下图。

在这里插入图片描述
1.用户请求过来之后,先查缓存有没有数据,如果有则直接返回。
2.如果缓存没数据,再继续查数据库。
3.如果数据库有数据,则将查询出来的数据,放入缓存中,然后返回该数据。
4.如果数据库也没数据,则直接返回空。

这是缓存非常常见的用法,一眼看上去,好像没有啥问题。但如果数据库中的某条数据,放入缓存之后,又立马被更新了,那么缓存中的数据就和数据库中的数据不一致了。

1.2 缓存不一致产生的原因

如果数据一直没有变更,那么就不会出现Redis和MySQL数据不一致性的问题。

两者之间数据不一致是因为一者发生了数据的变更,另一者如何在短时间内同步数据的问题。因为每次数据变更需要同时操作数据库和缓存,而他们又属于不同的系统,无法做到同时操作成功或失败,总会有一个时间差。在并发读写的时候可能就会出现缓存不一致的问题。

二、解决方案

缓存更新的设计方法大概有5种,下面分别对这四种方案进行描述。

2.1 先删除缓存,再更新数据库

  1. 这种方法在并发读写的情况下容易出现缓存不一致的问题。
    在这里插入图片描述

  2. 如上图所示,其可能的执行流程顺序为:
    1.客户端1 触发更新数据A的逻辑
    2.客户端2 触发查询数据A的逻辑
    3.客户端1 删除缓存中数据A
    4.客户端2 查询缓存中数据A,未命中
    5.客户端2 从数据库查询数据A,并更新到缓存中
    6.客户端1 更新数据库中数据A

可见,最后缓存中的数据A跟数据库中的数据A是不一致的,缓存中的数据A是旧的脏数据。因此一般不建议使用这种方式。

2.2 先更新数据库,删除缓存

  1. 这种方法在并发读写的情况下,也可能会出现短暂缓存不一致的问题。
    在这里插入图片描述
  2. 如上图所示,其可能执行的流程顺序为:
    1.客户端1 触发更新数据A的逻辑
    2.客户端2 触发查询数据A的逻辑
    3.客户端3 触发查询数据A的逻辑
    4.客户端1 更新数据库中数据A
    5.客户端2 查询缓存中数据A,命中返回(旧数据)
    6.客户端1 让缓存中数据A失效
    7.客户端3 查询缓存中数据A,未命中
    8.客户端3 查询数据库中数据A,并更新到缓存中

可见,最后缓存中的数据A和数据库中的数据A是一致的,理论上可能会出现一小段时间数据不一致,不过这种概率也比较低,大部分的业务也不会有太大的问题。

2.3 只更新缓存,由缓存自己同步更新数据库

  1. 只更新缓存,再由缓存去同步更新数据库。一个Write Through的例子如下:

在这里插入图片描述

  1. 如上图所示,其可能的执行流程顺序为:
    1.客户端1 触发更新数据A的逻辑
    2.客户端2 触发查询数据A的逻辑
    3.客户端1 更新缓存中的数据A,返回
    4.客户端2 查询缓存中的数据A,命中返回
    5.缓存异步更新数据A到数据库中

这种方式的优势是读写的性能都非常好,基本上只要操作完内存后就返回给客户端了,但是其是非强一致性,存在丢失数据的情况。

如果在缓存异步将数据更新到数据库中时,缓存服务挂了,此时未更新到数据库中的数据就丢失了。

2.4 只更新缓存,由缓存自己异步更新数据库

  1. 只操作更新缓存,再由缓存异步去更新数据库,例如:
    在这里插入图片描述
  2. 如上图所示,其可能的执行流程顺序为:
    1.客户端1 触发更新数据A的逻辑
    2.客户端2 触发查询数据A的逻辑
    3.客户端1 更新缓存中的数据A,返回
    4.客户端2 查询缓存中的数据A,命中返回
    5.缓存异步更新数据A到数据库中

这种方式的优势是读写的性能都非常好,基本上只要操作完内存后就返回给客户端了,但是其是非强一致性,存在丢失数据的情况。

如果在缓存异步将数据更新到数据库中时,缓存服务挂了,此时未更新到数据库中的数据就丢失了。

2.5 引入 MQ

在高并发的业务场景中,MQ(消息队列)是必不可少的技术之一。它不仅可以异步解耦,还能削峰填谷。对保证系统的稳定性是非常有意义的。MQ的生产者生产了消息之后,通过指定的topic发送到MQ服务器。然后MQ的消费者订阅该topic的消息,读取消息数据之后,做业务逻辑处理。使用MQ重试的具体方案如下:

在这里插入图片描述

  1. 当用户操作写完数据库,但删除缓存失败了,产生一条消息,发送给MQ服务器。
  2. 消费者读取MQ消息,重试5次删除缓存。如果其中有任意一次成功了,则返回成功。如果重试了5次,还是失败,则写入死信队列中。
  3. 推荐MQ使用RocketMQ,重试机制和死信队列默认是支持的。使用起来非常方便,而且还支持顺序消息,延迟消息和事务消息等多种业务场景。

当然在该方案中,删除缓存可以完全走异步。即用户的写操作,在写完数据库之后,不用立刻删除一次缓存。而直接发送消息,到MQ服务器,然后有消费者全权负责删除缓存的任务。因为MQ的实时性还是比较高的,因此改良后的方案也是一种不错的选择。

三、总结

1.我们能放入缓存的数据本就不应该是实时性、一致性要求超高的。所以缓存数据的时候加上过期时间,保证能够再容忍的时间段内拿到当前最新数据即可。
2.我们不应该过度设计,增加系统的复杂性。
3.遇到实时性、一致性要求高的数据,就应该查数据库,即使慢点。

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

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

相关文章

【MybatisPlus篇】查询条件设置(范围匹配 | 模糊匹配 | 空判定 | 包含性判定 | 分组 | 排序)

文章目录 🎄环境准备⭐导入依赖⭐写入User类⭐配置启动类⭐创建UserDao 的 MyBatis Mapper 接口,用于定义数据库访问操作⭐创建配置文件🛸创建测试类MpATest.java 🍔范围查询⭐eq⭐between⭐gt 🍔模糊匹配⭐like &…

力扣之2629.复合函数(reduceRight )

/*** param {Function[]} functions* return {Function}*/ var compose function(functions) {return function(x) {return functions.reduceRight((result, func) > func(result), x);} };/*** const fn compose([x > x 1, x > 2 * x])* fn(4) // 9*/ 说明&#x…

docker 容器指定主机网段

docker 容器指定主机网段。 直接连接到物理网络:使用macvlan技术可以让Docker容器直接连接到物理网络,而不需要通过NAT或端口映射的方式来访问它们。可以提高网络性能和稳定性,同时也可以使容器更加透明和易于管理。 1、查询网卡的名称&…

微软Office Plus与WPS Office的较量:办公软件市场将迎来巨变?

微软Office Plus在功能表现上远超WPS Office? 微软出品的Office套件实力强劲,其不仅在办公场景中扮演着不可或缺的角色,为用户带来高效便捷的体验,而且在娱乐生活管理等多元领域中同样展现出了卓越的应用价值 作为中国本土办公软…

c语言--求第n个斐波那契数列(递归、迭代)

目录 一、概念二、用迭代求第n个斐波那契数1.分析2.完整代码3.运行结果4.如果求第50个斐波那契数呢?看看会怎么样。4.1运行结果:4.2画图解释 三、用迭代的方式求第n个斐波那契数列1.分析2.完整代码3.运行结果4.求第50个斐波那契数4.1运行结果4.2运行结果…

基于粒子群算法的多无人机任务分配

python3.6以上正常运行 基于粒子群算法的多无人机任务分配资源-CSDN文库

在Flutter中调用Android的代码

参考 【Flutter 混合开发】嵌入原生View-Android 默认使用Android studio 和 Kotlin 基本配置 创建flutter项目 在终端执行 flutter create batterylevel添加 Android 平台的实现 打开项目下的android/app/src/main/kotlin 下的 MainActivity.kt 文件。 我这里编辑器有…

开源的三维算法库有哪些

PCL,VTK,VCG,CGAL,Open CASCADE(opencascade),OpenSceneGraph (OSG),Easy3D 点云网格处理算法:openmesh, meshlab三维算法库,Eigen 网格简化,网格平滑,网格参数化 无序…

北朝隋唐文物展亮相广西,文物预防性保护网关保驾护航

一、霸府名都——太原博物馆收藏北朝隋朝文物展 2月1日,广西民族博物馆与太原博物馆携手,盛大开启“霸府名都——太原博物馆北朝隋文物展”。此次新春展览精选了北朝隋唐时期150多件晋阳文物珍品。依据“巍巍雄镇”“惊世古冢”“锦绣名都”三个单元&am…

Java swing —— 创建一个窗口

swing组件分类: 顶层容器:JFrame、JApplet、JDialog、JWindow 中间容器:JPanel、JScrollPane、JSplitPane、JToolBar 基本控件: ImageIcon(图标),JLabel(标签)&#xff…

【数据结构】分治策略

现场保护和现场恢复 文章目录 分治策略分治法解决问题有以下四个特征:分治法步骤: 递归:解决以下问题:倒序输出整数求最大公约数(递归和非递归)菲波那切数列 不要尝试间接 要使用直接递归(自己调用自己&am…

代码随想录算法训练营第二十四天|● 理论基础 ● 77. 组合

仅做学习笔记,详细请访问代码随想录 ● 理论基础 ● 77. 组合 ● 理论基础 回溯法解决的问题 回溯法,一般可以解决如下几种问题: 组合问题:N个数里面按一定规则找出k个数的集合 切割问题:一个字符串按一定规则有几…

SpringBoot统一功能处理,拦截器,统一数据格式,捕捉异常

目录 拦截器:是Spring框架提供的核心功能之一,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码: 自定义拦截器 统一数据格式,要包含状态码,错误信息​编辑 出现针对String类型的错误​​​…

MySQL查询缓存

MySQL查询缓存 MySQL在查询的时候首先会查询缓存,如果缓存命中的话就直接返回结果,不需要解析sql语句,也不会生成执行计划,更不会执行;如果没有命中缓存,则再进行SQL解析以及进行查询,并将结果返…

CodeFuse成功支持通义千问算法大赛,评测方案已开源

前段时间, 首届通义千问AI挑战赛成功举办,CodeFuse 为大赛提供技术支持,模型微调框架 MFTCoder 和 CodeFuseEval 评测框架为大赛保驾护航,助力大赛圆满完成。我们基于leetcode 阿里和蚂蚁最新面试题库建设了“模型赛马”在线打榜的…

NC、NC65、NCC富客户端附件在线预览插件

NC附件目前只支持下载,不支持在线查看 通过二开实现NC的附件可以在线预览 支持的格式包含:doc, docx, xls, xlsx, ppt, pptx, pdf和txt等。

金和OA jc6 UploadFileBlock 任意文件上传漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

使用JDBC连接mysql

JDBC:Java DataBase Connectivity,Java数据库连接。 使用Java语言操作关系型数据库的一套API。 原理:官方(sun公司)定义出一套操作所有关系型数据库的规则,即接口;所有的数据库厂商去实现这套接口,提供数据…

Kubernetes k8s

Kubernetes k8s 一个开源的容器编排引擎,用来对容器化应用进行自动化部署、 扩缩和管理。 从架构设计层面,k8s能很好的解决可用性,伸缩性;从部署运维层面,服务部署,服务监控,应用扩容和故障处…

大数据信用报告查询费用一般要多少钱?

一些不少朋友在申贷的时候被拒贷之后,得到的原因就是因为大数据不良被拒,这时候很多人都反过来查询自己的大数据信用报告,而查询的价格也是不少朋友都比较关注的,那大数据信用报告查询费用一般要多少钱呢?下面本文就为你介绍一下…