4 种策略让 MySQL 和 Redis 数据保持一致

先阐明一下 MySQL 和 Redis 的关系:MySQL 是数据库,用来持久化数据,一定程度上保证数据的可靠性;Redis 是用来当缓存,用来提升数据访问的性能。

关于如何保证 MySQL 和 Redis 中的数据一致(即缓存一致性问题),这是一个非常经典的问题。

使用过缓存的人都应该知道,在实际应用场景中,要想实时刻保证缓存和数据库中的数据一样,很难做到。

基本上都是尽可能让他们的数据在绝大部分时间内保持一致,并保证最终是一致的。

1、缓存不一致是如何产生的

如果数据一直没有变更,那么就不会出现缓存不一致的问题。

通常缓存不一致是发生在数据有变更的时候。因为每次数据变更你需要同时操作数据库和缓存,而他们又属于不同的系统,无法做到同时操作成功或失败,总会有一个时间差。在并发读写的时候可能就会出现缓存不一致的问题(理论上通过分布式事务可以保证这一点,不过实际上基本上很少有人这么做)。

虽然没办法在数据有变更时,保证缓存和数据库强一致,但对缓存的更新还是有一定设计方法的,遵循这些设计方法,能够让这个不一致的影响时间和影响范围最小化。

2、缓存更新的几种设计

缓存更新的设计方法大概有以下四种:

先删除缓存,再更新数据库(这种方法在并发下最容易出现长时间的脏数据,不可取)

先更新数据库,删除缓存(Cache Aside Pattern)

只更新缓存,由缓存自己同步更新数据库(Read/Write Through Pattern)

只更新缓存,由缓存自己异步更新数据库(Write Behind Cache Pattern)

接下来详细介绍一些这四种设计方法

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

这种方法在并发读写的情况下容易出现缓存不一致的问题
在这里插入图片描述
如上图所示,其可能的执行流程顺序为:

客户端1 触发更新数据A的逻辑

客户端2 触发查询数据A的逻辑

客户端1 删除缓存中数据A

客户端2 查询缓存中数据A,未命中

客户端2 从数据库查询数据A,并更新到缓存中

客户端1 更新数据库中数据A

可见,最后缓存中的数据 A 跟数据库中的数据 A 是不一致的,缓存中的数据A是旧的脏数据。

因此一般不建议使用这种方式。

2.2 先更新数据库,再让缓存失效

这种方法在并发读写的情况下,也可能会出现短暂缓存不一致的问题
在这里插入图片描述
如上图所示,其可能执行的流程顺序为:

客户端1 触发更新数据A的逻辑

客户端2 触发查询数据A的逻辑

客户端3 触发查询数据A的逻辑

客户端1 更新数据库中数据A

客户端2 查询缓存中数据A,命中返回(旧数据)

客户端1 让缓存中数据A失效

客户端3 查询缓存中数据A,未命中

客户端3 查询数据库中数据A,并更新到缓存中

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

2.3 只更新缓存,由缓存自己同步更新数据库(Read/Write Through Pattern)

这种方法相当于是业务只更新缓存,再由缓存去同步更新数据库。一个Write Through的 例子如下:
在这里插入图片描述
如上图所示,其可能执行的流程顺序为:

客户端1 触发更新数据 A 的逻辑

客户端2 触发查询数据 A 的逻辑

客户端1 更新缓存中数据 A,缓存同步更新数据库中数据 A,再返回结果

客户端2 查询缓存中数据 A,命中返回

Read Through 和 WriteThrough 的流程类似,只是在客户端查询数据A时,如果缓存中数据A失效了(过期或被驱逐淘汰),则缓存会同步去数据库中查询数据A,并缓存起来,再返回给客户端。

这种方式缓存不一致的概率极低,只不过需要对缓存进行专门的改造。

2.4 只更新缓存,由缓存自己异步更新数据库(Write Behind Cache Pattern)

这种方式性详单于是业务只操作更新缓存,再由缓存异步去更新数据库,例如:
在这里插入图片描述
如上图所示,其可能的执行流程顺序为:

客户端1 触发更新数据 A 的逻辑

客户端2 触发查询数据 A 的逻辑

客户端1 更新缓存中的数据 A,返回

客户端2 查询缓存中的数据 A,命中返回

缓存异步更新数据 A 到数据库中

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

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

上面讲到的几种缓存更新的设计方式,都是前人总结出来的经验,这些方式或多或少都有一些弊端,并不完美,实际上也很难有完美的设计。大家在做系统设计的时候,也不要去追求完美,要有一些取舍,找到一种最适合自己业务场景的方式就行。

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

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

相关文章

2_怎么看原理图之协议类接口之UART笔记

通信双方先约定通信速率,如波特率115200 一开始时,2440这边维持高电平 1> 开始发送时,由2440将(RxD0)高电平拉低,并持续一个T的时间(为了让PC机可以反应过来),T1/波…

汇编语言movs指令学习

字符串传送指令(Move String Instruction) movs 该指令是把指针DS:SI所指向的字节、字或双字传送给指针ES:DI所指向内存单元,并根据标志位DF对寄存器DI和SI作相应增减。该指令的执行不影响任何标志位。 记不清这指令是8086就有的,还是386以后新加的&…

C# OpenVINO PaddleSeg实时人像抠图PP-MattingV2

目录 效果 项目 代码 下载 C# OpenVINO 百度PaddleSeg实时人像抠图PP-MattingV2 效果 项目 代码 using OpenCvSharp; using Sdcb.OpenVINO; using System; using System.Diagnostics; using System.Drawing; using System.Security.Cryptography; using System.Text; us…

一种新型的AlGaN/GaN HEMTs小信号建模与参数提取方法

来源:A new small-signal modeling and extraction methodin AlGaN/GaN HEMTs(SOLID-STATE ELECTRONICS 07年) 摘要 本文提出了一种新型的用于GaN HEMTs(氮化镓高电子迁移率晶体管)的小信号等效电路,包含2…

Edting While Playing 瓦片地图编辑器开发整合导入自定义贴图 DEVC++ VS2022都可复制粘贴运行

接 多种类型图片模块读取-CSDN博客 与 Editing While Playing 使用 Easyx 开发的 RPG 地图编辑器 tilemap eaitor-CSDN博客 整合实现平面贴图纹理自定义 操作同上 导入步骤: 先运行程序,然后关闭,同目录下有四个文件夹, 把…

模型评估方式

文章目录 一、有监督-分类模型1、混淆矩阵2、分类模型的精度和召回率3、ROC曲线与AUC 二、有监督-回归模型1、均方误差MSE2、 R 2 R^2 R2决定系数3、回归模型代码示例 三、无监督模型1、kmeans求解最优k值的方法:轮廓系数、肘部法2、GMM的最优组件个数:A…

Vue+SpringBoot打造快递管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 数据中心模块2.2 快递类型模块2.3 快递区域模块2.4 快递货架模块2.5 快递档案模块 三、界面展示3.1 登录注册3.2 快递类型3.3 快递区域3.4 快递货架3.5 快递档案3.6 系统基础模块 四、免责说明 一、摘要 1.1 项目介绍 …

vue3中ref创建变量取值时自动补充 .value 插件 volar

插件 TypeScript Vue Plugin (Volar) 设置中配置

进阶了解C++(2)——复杂的继承及其底层原理

在上篇文章中,给出了关于继承这部分的相关知识,例如继承的定义,继承与默认成员函数等。本文将针对复杂的继承方式, 1. 复杂的继承方式: 1.1 单继承: class Professor { public:int _age;string _name; }…

Windows安装HBuilderX

下载 HBuilderX下载地址: 下载地址 解压安装包 HBuilderX,Windows为zip包,解压后才能使用。 首先,选中下载的zip包,点击右键菜单,点击解压到当前文件夹进入解压后的文件夹,找到HBuilderX.exe&#xff0…

计算机组成原理(13)-----硬件多线程

目录 1.细粒度多线程 2.粗粒度多线程 3.同时多线程(SMT) 在不支持硬件多线程的处理器中,若要进行线程的切换,就需要保存和恢复线程的运行环境(否则会出现数据覆盖引起的错误)。 但在支持硬件多线程的处…

Android java中包的使用

一.包的使用 为了更好的实现项目中类的管理,提供包的概念。 package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。 它的格式为:package 顶层包名.子包名 ; 二.java中主要的包…

算法分析-面试1-字符串

文章目录 前言一、分类:看看就行了二、字符串API:创建和初始化:查询操作:比较操作:修改操作:截取操作:分割操作:格式化操作:连接操作(Java 8 及以后&#xff…

Delphi 11 安卓的蓝牙权限申请

上一篇博客里面的代码,演示如何申请安卓的权限。 如何申请安卓的蓝牙权限? 本博客之前有一篇文章写过。 现在 Google 要求 Android API Level 必须是 33。对于 BLE 的权限申请,有了一些新的要求。 以下描述,基于 Delphi 11。 …

vue页面基本增删改查

练手项目vue页面 新手前端轻喷: 效果如下 1、2两个部分组成: 对应代码中 element-ui中的 el-form 和 el-table 照着抄呗,硬着头皮来! 建议:认真读一遍你用的组件 那上边简单得列表举例: 建议大家手敲一个…

Unity与Android交互通信系列(5)

在前述文章中,已经使用了AndroidJavaProxy代理接口,本节我们将详细的介绍AndroidJavaProxy代理的用法。正如其名,AndroidJavaProxy是一个代理,它在Android端代码与Unity端代码交互中起一个桥接作用。其一般用法为在Java代码中定义…

【深度学习】主要提出者【Hinton】中国大会最新演讲【通往智能的两种道路】

「但我已经老了,我所希望的是像你们这样的年轻有为的研究人员,去想出我们如何能够拥有这些超级智能,使我们的生活变得更好,而不是被它们控制。」 6 月 10 日,在 2023 北京智源大会的闭幕式演讲中,在谈到如…

一键生成PDF即刻呈现:轻松创建无忧体验

在信息爆炸的时代,我们每天都在与各种文件、资料打交道。无论是工作中的报告、合同,还是学习中的笔记、论文,如何高效、安全地管理这些珍贵的资料,成为了我们迫切的需求。幸运的是,随着科技的发展,我们不再…

SpringBoot Admin 详解

SpringBoot Admin 详解 一、Actuator 详解1.Actuator原生端点1.1 监控检查端点:health1.2 应用信息端点:info1.3 http调用记录端点:httptrace1.4 堆栈信息端点:heapdump1.5 线程信息端点:threaddump1.6 获取全量Bean的…

【Python笔记-设计模式】享元模式

一、说明 享元模式是一种结构型设计模式,它摒弃了在每个对象中保存所有数据的方式,通过共享多个对象所共有的相同状态,让你能在有限的内存容量中载入更多对象。 (一) 解决问题 旨在减少大量相似对象创建时的内存开销 (二) 使用场景 大量…