MySQL与Redis缓存一致性的实现与挑战

缓存是提高应用性能的重要手段之一,而 MySQL 和 Redis 是两种常用的数据存储和缓存技术。在许多应用中,常常将 Redis 用作缓存层,以加速对数据的访问。然而,在使用 MySQL 和 Redis 组合时,保持缓存与数据库之间的一致性是一个不得不考虑的问题。

一、缓存一致性的挑战

MySQL 和 Redis 之间的缓存一致性涉及到两个方面:

数据一致性

数据在 MySQL 和 Redis 中的一致性是指在对数据进行更新操作时,确保MySQL 和 Redis 中的数据保持同步。如果 Redis 中的缓存数据与 MySQL 数据库中的数据不一致,可能会导致应用程序出现错误以及一些未知的问题。

缓存有效性

缓存有效性是指 Redis 中的缓存数据是否仍然有效,是否需要更新或者过期。如果 Redis 中的缓存数据过期,但 MySQL 中的数据已经更新,可能会导致从 Redis 中获取到的数据不准确。

再说实现缓存与数据库数据一致性的实现方法之前,我们先来了解一下什么是缓存模式?

之前写过一篇关于缓存模式的文章,可以跳过去了解一下。

缓存模式

直接往下看也可以,我在这篇文章里面会重新对几种缓存模式进行一下介绍,并加以配图说明。

二、缓存模式有哪些

如果你读过上面缓存模式那篇文章的话,相信你对缓存模式应该有一定的了解了,如果不了解也没关系,我们一起来看看吧。

2.1、Cache Aside

最常用的缓存模式,大体意思是先从 cache 中取数据,没有获取到则从数据库中读取,成功后放到缓存中;

如果在 cache 中获取到数据直接返回;

更新时先把数据存到数据库,成功后再让缓存失效。

  • 先更新数据库,再更新缓存

遇到的问题是两个并发的更新操作,数据库先更新的后更新缓存,数据库后更新的先更新缓存,这样就会造成数据库与缓存的数据不一致,应用程序中读取的数据都是脏数据

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

遇到的问题是有两个并发操作,一个更新操作先删除了缓存,此时另一个并发的读取操作没有命中缓存,直接读取数据库并更新回了缓存,这个时候正好更新操作完成数据更新。此时数据库和缓存的数据不一致,应用程序读取的数据都脏数据了

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

这个方式也算是我们实际系统使用中比较推荐的一种方式,但是这种方式在理论上还是可能会出现问题,两个并发操作,其中一个查询操作没有命中缓存,此时查询出来了数据库中的老数据,此时另一个并发的更新操作,在刚才的并发读操作之后更新了数据库中的数据并删除了缓存,然后并发读操作线程又把老数据写入了缓存,此时又造成了数据的不一致,应用程序读取的都是脏数据。因为这种概率差生的情况实在是太小,所以才是我们系统中经常使用的一种方式了。

2.2、Read/Write Through

Cache Aside 模式中,应用程序需要维护两个数据存储,一个是缓存,一个是数据库,在 Read/Write Through 更新模式中,应用程序只需要维护缓存,数据库的维护工作就有缓存代理了

2.2.1、Read Through

Read Through 模式就是在查询时更新缓存,也就是说,在缓存失效时,Cache Aside 模式是由调用方负责把数据载入缓存,而 Read Through 模式是缓存服务自己更新缓存,自己来加载数据。

当应用程序执行读操作时,如果缓存中不存在所需数据,则缓存会自动从数据源(如数据库)中读取数据,并将数据加载到缓存中,然后返回给应用程序。

Read-Through 策略减少了应用程序与数据源之间的直接交互次数,提高了读操作的性能和响应速度。

2.2.2 Write Through

Write Through 和 Read Through 类似,当数据更新时,如果命中缓存则更新缓存,然后缓存更新数据库,这是一个同步的操作;如果没有命中缓存,直接更新数据库返回。

Write-Through 策略保证了缓存和数据源中的数据一致性,但由于每次写操作都需要等待数据源的确认,可能会影响写操作的性能和延迟。

2.3、 Write Behind Caching

Write Behind Caching 更新模式是在更新数据时只更新缓存,不更新数据库,而我们的缓存会异步的更新数据库。这个模式的话就是速度快,毕竟我们直接操作内存,因为是异步的,Write Behind Caching 更新模式还可以合并对同一个数据的多次操作到数据库,所以性能的提升也是很明显的

问题就是数据不是强一致性的,而且还可能会丢失,Write Behind Caching 更新模式实现逻辑复杂,因为它需要确认有哪些数据是被更新的,哪些数据是需要刷到持久层的数据库的。只有当缓存失效的时候才会把它真正的持久化起来。

Write-Behind 策略提高了写操作的性能和响应速度,但在写入缓存后,数据源中的数据可能会落后于缓存中的数据一段时间,存在一定的数据一致性风险。

三、一致性有哪些

说到一致性,我们应该想到的就是分布式系统中多个节点对看到的数据副本都保持一致的特性。换个说法就是,无论用户在哪个节点上执行操作,最终所有节点上的数据是相同的,且满足一定的约束条件。

在分布式系统中,实现一致性是很困难的,因为系统中的多个节点可能会因为网络延迟,节点故障或者其他的因素导致多个数据副本之间的状态不一致。为了实现分布式系统中的一致性,业界常用的算法和协议有 PaxosRaftZAB

分布式系统的一致性又分为强一致性、弱一致性、最终一致性。

  • 强一致性:最严格的一致性,相当于对于用户来说是最友好的。因为这个相当于系统写入的是什么数据,读取时也就是什么数据。

  • 弱一致性:相比于强一致性,弱一致性不承诺立即读取最新的值,也不承诺多久之后数据一致。但是会尽可能的保证在到达某个时间点之后,数据达到一致状态。

  • 最终一致性:最终一致性是弱一致性的一个特例,保证在一定时间之后达到数据一致状态,因此最终一致性也是目前业界来说最推崇的模型。

四、一致性实现方法

4.1、双写

双写其实就是 Write Through 模式,在写入 MySQL 数据库的同时,立即写入 Redis 缓存。这样可以确保 MySQL 和 Redis 中的数据保持一致,但增加了写入的延迟,并且增加了系统复杂度。

4.1.1、双写为什么先操作数据库在操作缓存?

我们来看如下的例子,线程A线程B 是一组并发请求。

1、线程A 发起一个写请求、先删除 Redis 中的缓存。

2、线程B 发起一个读请求,没有命中缓存。

3、线程B 读取数据库,获取数据。

4、线程B 写入老数据到缓存。

5、线程A 写入DB 新数据。

到这就发现了问题了吧,如果你没发现,那就跟着我的思路来看一下。

大家来看第三步,线程B 去读取数据库,此时 线程A 是还没有写入新数据的,所以此时 线程B 读取的数据是老数据。

而第5步,线程A 往数据库写入的才是最新的数据。

所以此时也就造成了数据不一致 了。

对于这种情况造成的脏数据缓存,有的小伙伴可能就提出来了,可以使用缓存双删啊,那么我们来继续往下看。

4.1.2、缓存延迟双删

延迟双删,就是字面意思,删除两边缓存。你知道问题在哪吗,想一想?

。。。。。。

双删,有可能删除失败吗?

删除失败怎么办?

双删的步骤如下

1、删除缓存。

2、更新数据库。

3、延迟删除(此时延迟的差不多是读请求的耗时多一点,防止读请求设置脏数据缓存)。

4.1.3、删除缓存的重试机制

删除缓存失败,第一个想到的应该是,删除失败了就多删除几次吧。

所以我们可以借助于消息队列,将删除失败的 key 加入到消息队列,对消息进行重试删除操作。

既然我们都用到消息队列了,那么我们为什么不直接监听 binlog 实现异步删除缓存呢。

4.2、消息队列

使用消息队列监听数据库变更事件、异步更新缓存。能够保证在数据库更新后,缓存能够按照顺序进行更新。

此时的例子就是,使用 Canal 监听 binlog ,发送数据到 MQ 中,应用程序监听 MQ 消息实现 Redis 缓存的更新。

五、总结

实现 MySQLRedis缓存的一致性中,需要考虑很多的方面,最直观的就是业务场景,性能要求,以及数据的安全等因素综合考虑。

例如,对于读多写少的场景,可以采用 Read/Write Through 模式;

而对于写操作频繁的场景,则可能需要考虑 Write Behind Caching 模式。

如果这篇文章对您有所帮助,或者有所启发的话,帮忙点个关注一下,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

wx 搜索《醉鱼Java》,回复面试、获取2024面试资料

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【MATLAB源码-第54期】基于白鲸优化算法(WOA)和遗传算法(GA)的栅格地图路径规划最短路径和适应度曲线对比。

操作环境: MATLAB 2022a 1、算法描述 1.白鲸优化算法(WOA): 白鲸优化算法是一种受白鲸捕食行为启发的优化算法。该算法模拟了白鲸群体捕食的策略和行为,用以寻找问题的最优解。其基本思想主要包括以下几点&#xff…

FMEA赋能可穿戴设备:打造安全可靠的未来科技新宠!

在科技日新月异的今天,可穿戴设备已成为我们生活中不可或缺的一部分。它们以其便携性、智能化和个性化的特点,深受消费者喜爱。然而,随着可穿戴设备市场的快速扩张,其安全性和可靠性问题也日益凸显。为了确保产品质量,…

QT常量中有换行符解决方法--使用中文显示乱码或者编译报错

QT6.3常量中有换行符 int ret2QMessageBox::information(this,QString::fromLocal8Bit("提示"),QString::fromLocal8Bit(("确认启动设备吗?")),QMessageBox::Yes,QMessageBox::No); 确保显示正常,建议每次使用时,中文的前后加一个空…

从零开始写 Docker(十一)---实现 mydocker exec 进入容器内部

本文为从零开始写 Docker 系列第十一篇,实现类似 docker exec 的功能,使得我们能够进入到指定容器内部。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识: 核心原理&…

在线音乐网站的设计与实现

在线音乐网站的设计与实现 摘 要 在社会和互联网的快速发展中,音乐在人们生活中也产生着很大的作用。音乐可以使我们紧张的神经得到放松,有助于开启我们的智慧,可以辅助治疗,达到药物无法达到的效果,所以利用现代科学…

优秀Burp插件 提取JS、HTML中URL插件

Burp Js Url Finder 攻防演练过程中,我们通常会用浏览器访问一些资产,但很多接口/敏感信息隐匿在html、JS文件中,通过该Burp插件我们可以: 1、发现通过某接口可以进行未授权/越权获取到所有的账号密码 2、发现通过某接口可以枚举用…

STM32的GPIO端口的八种模式解析

目录 STM32的GPIO端口的八种模式解析 一、上拉输入模式 二、下拉输入模式 三、浮空输入模式 四、模拟输入模式 五、推挽输出模式 六、开漏输出模式 七、复用推挽输出模式 八、复用开漏输出模式 STM32的GPIO端口的八种模式解析 在学习STM32的过程中,GPIO端口…

【YUV】YUV图像全面详解(一)——格式详解

文章目录 一、前言二、YUV 介绍三、YUV 优点四、YUV 采样格式五、YUV 存储格式六、具体分类详解 一、前言 视频采集芯片输出的码流一般都是 YUV 格式数据流,后续视频处理也是对 YUV 数据流进行编码和解析。所以,了解 YUV 数据流对做视频领域的人而言&am…

【web开发网页制作】html+css家乡长沙旅游网页制作(4页面附源码)

家乡长沙网页制作 涉及知识写在前面一、网页主题二、网页效果Page1、主页Page2、历史长沙Page3、著名人物Page4、留言区 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 四、网页源码HtmlCSS 五、源码获取5.1 获取方式 作者寄语 涉及知识 家乡长沙网页制作&#x…

学习Rust的第5天:控制流

Control flow, as the name suggests controls the flow of the program, based on a condition. 控制流,顾名思义,根据条件控制程序的流。 If expression If表达式 An if expression is used when you want to execute a block of code if a condition …

如何试用 Ollama 运行本地模型 Mac M2

首先下载 Ollama https://github.com/ollama/ollama/tree/main安装完成之后,启动 ollma 对应的模型,这里用的是 qwen:7b ollama run qwen:7b命令与模型直接交互 我的机器配置是M2 Pro/ 32G,运行 7b 模型毫无压力,而且推理时是用…

C语言案例——输出以下图案(两个对称的星型三角形)

目录 图片代码 图片 代码 #include<stdio.h> int main() {int i,j,k;//先输出上半部图案for(i0;i<3;i){for(j0;j<2-i;j)printf(" ");for(k0;k<2*i;k)printf("*");printf("\n");}//再输出下半部分图案for(i0;i<2;i){for(j0;j&…

《R语言与农业数据统计分析及建模》学习——R基础包的函数

1、R的基础包 基础包是R语言的核心组成部分&#xff0c;构建了R语言的基本功能框架。是R语言默认的安装包&#xff0c;不需要额外安装&#xff0c;使用时无需加载。 2、常用函数及其功能 &#xff08;1&#xff09;数据处理函数&#xff1a;unique()、sort()、subset() # 获…

LRTimelapse for Mac:专业延时摄影视频制作利器

LRTimelapse for Mac是一款专为Mac用户设计的延时摄影视频制作软件&#xff0c;它以其出色的性能和丰富的功能&#xff0c;成为摄影爱好者和专业摄影师的得力助手。 LRTimelapse for Mac v6.5.4中文激活版下载 这款软件提供了直观易用的界面&#xff0c;用户可以轻松上手&#…

OpenHarmony、HarmonyOS和Harmony NEXT 《我们不一样》

1. OpenHarmony 定义与地位&#xff1a;OpenHarmony是鸿蒙系统的底层内核系统&#xff0c;集成了Linux内核和LiteOS&#xff0c;为各种设备提供统一的操作系统解决方案。 开源与商用&#xff1a;OpenHarmony是一个开源项目&#xff0c;允许开发者自由访问和使用其源代码&#…

# Nacos 服务发现-Spring Cloud Alibaba 综合架构实战(五) -实现 gateway 网关。

Nacos 服务发现-Spring Cloud Alibaba 综合架构实战&#xff08;五&#xff09; -实现 gateway 网关。 1、什么是网关&#xff1f; 原来的单体架构&#xff0c;所有的服务都是本地的&#xff0c;UI 可以直接调用&#xff0c;现在按功能拆分成独立的服务&#xff0c;跑在独立的…

Kafka、RabbitMQ、Pulsar、RocketMQ基本原理和选型

Kafka、RabbitMQ、Pulsar、RocketMQ基本原理和选型 1. 消息队列1.1 消息队列使用场景1.2. 消息队列模式1.2.1 点对点模式&#xff0c;不可重复消费1.2.2 发布/订阅模式 2. 选型参考2.1. Kafka2.1.1 基本术语2.1.2. 系统框架2.1.3. Consumer Group2.1.4. 存储结构2.1.5. Rebalan…

【深度学习】执行wandb sync同步命令报错wandb: Network error (SSLError), entering retry loop

执行wandb sync同步命令报错wandb: Network error (SSLError), entering retry loop 在代码中设置wandb offline的命令 os.environ["WANDB_API_KEY"] "API keys" os.environ["WANDB_MODE"] "offline"日志文件生成后&#xff0c;使…

十大排序——7.希尔排序

下面我们来看一下希尔排序 目录 1.介绍 2.代码实现 3.总结与思考 1.介绍 希尔排序是插入排序的一种优化&#xff0c;可以理解为是一种分组的插入排序。 希尔排序的要点&#xff1a; 简单来说&#xff0c;就是分组实现插入&#xff0c;每组元素的间隙称为gap&#xff0c;…

【Git】常用命令速查

目录 一、创建版本 二、修改和提交 三、查看提交历史 四、撤销 五、分支与标签 六、合并与衍合 七、远程操作 一、创建版本 命令简要说明注意事项git clone <url>克隆远程版本库 二、修改和提交 命令简要说明注意事项 三、查看提交历史 命令简要说明注意事项 …