如何实现Redis和Mysql中数据双写一致性
在我们的实际开发中,我们用到了redis缓存一些常用的数据(如热点数据)用来提高系统的吞吐量。 但是不可以避免的出现了数据的修改场景,这就导致了数据库中的数据和Redis中出现不一致性的情况。如何保证数据一致性就显得非常重要了,下面介绍一下保证数据的双写一致性的方案。
1、先删缓存再操作数据库方案
在redis一般写的场景下对数据的更新操作是不推荐使用的,推荐使用删除缓存数据的操作,因为删除操作的效率更高。下图展示先删除缓存再操作数据库的过程图:

在这种方式下会存在数据不一致的问题,如下图所示:

(1)线程1要更新数据,它先删除redis中的缓存数据,然后由于网络堵塞导致暂短的停顿,没有继续执行操作数据库
(2)线程2要查询数据,首先查询数据库,但是由于Redis中的数据已经被线程1删除了,那么它会去数据库中查询数据X并且要将数据X同步到Redis中
(3)线程1网络堵塞结束,执行了数据库操作将数据X更改为Y
经过上述的过程就导致了Redis的数据和数据库中的数据不一致了,即就是Redis中存放的依据是老数据。为了解决上述的问题,我们采用缓存延迟双删的策略,如下图所示的缓存延迟双删的过程:

采用缓存延迟双删策略最多在X毫秒内读取的数据是老数据,在X毫秒之后读取的数据都是最新的数据。X的具体值如何确定那就需要根据自身的业务了来确定。
延迟双删策略只能保证最终的一致性,不能保证强一致性。由于对Redis的操作和Mysql的操作不是原子性操作,所以如果想保证数据的强一致性就需要加锁控制,如下图所示:

加锁之后势必会带来系统的吞吐量的下降,所以需要衡量利弊来确定是否使用加锁。
2、先操作数据库再删除缓存方案

此方案就是先操作数据库,数据库写入成功之后再来删除Redis缓存中的数据。多个线程之间的数据读取和更新如下图所示:

这种方案下,在数据库更新成功后到删除Redis缓存数据之前的这段时间中,其他线程读取的数据都是旧数据,等Redis删除缓存后会重新从数据库中读取最新数据同步到Redis,这样可以在一定程度上保证数据的最终一致性。极端情况下会出现数据不一致的情况,如下图所示:

(1)线程1先成功的更新数据到数据库中,然后执行删除Redis缓存中的数据的时候失败了
(2)线程2要读取数据,此时优先从Redis中查询数据,由于此时Redis中老数据没有删除,所以线程2可以拿到旧数据直接返回。直到Redis中缓存的数据过期之后才可以从数据库中获取最新的到Redis中
3、删除重试机制
无论是先删除缓存再操作数据还是先操作数据库再删除缓存的机制,都有可能会出现删除缓存失败的情况,如下图所示:

为了应对删除缓存失败的情况发生,于是加入了删除重试机制,如下图所示:

通过canal监听binlog感知数据的变动后,canal客户端执行删除Redis缓存数据,如果缓存数据删除失败那么发送一条MQ消息让canal客户端继续执行删除操作,这样可以保证数据的最终一致性。但是这样也增加了系统的复杂性。
4、总结:
(1)实际开发中推荐使用先操作数据库再删除缓存的方案,因为此方案最大程度上保证了数据的一致性并且实现也最简单。
(2)无论是先操作数据库再删除缓存还是先删除缓存再操作数据库都有可能会出现删除缓存失败的情况,所以需要加入删除重试机制。
(3)如果想要Redis和Mysql的数据强一致性,可以考虑使用加锁的方式实现。
5、实际应用
在实际应用中,我们一般会采取云服务器使用并处理实时同步RDS与Redis构建缓存一致性,可参考我的上一篇文章:实时同步RDS与Redis构建缓存一致性-CSDN博客
通过DTS数据订阅能力,用户可以实时订阅RDS日志数据变更,并将其写入Redis以实现缓存数据的更新。这样的配置可以实现MySQL与Redis之间的缓存同步一致性,采用了Cache-Aside Pattern模式。通过DTS的服务化能力,用户可以保证高效、稳定和实时的数据同步。从而用户能够实现商品信息的实时同步,确保在系统中的商品信息始终是最新的。同时,对于账单信息的查询也能够变得高效,用户可以从Redis中获取已缓存的数据,减少对MySQL的频繁访问,提升查询性能。这样的解决方案不仅能够提高系统的响应速度,还能够保证数据的一致性和准确性,为用户提供更好的使用体验。
我使用的服务器组合是云服务器ECS省钱攻略,可以试用。

通过RDS MySQL+DTS+Redis的架构,实现RDS MySQL与Redis缓存之间的数据同步和一致性。通过实时同步MySQL数据库数据到Redis缓存,提高数据查询速度,降低数据库压力,确保业务数据的实时性和准确性。
相关文章:
如何实现Redis和Mysql中数据双写一致性
在我们的实际开发中,我们用到了redis缓存一些常用的数据(如热点数据)用来提高系统的吞吐量。 但是不可以避免的出现了数据的修改场景,这就导致了数据库中的数据和Redis中出现不一致性的情况。如何保证数据一致性就显得非常重要了&…...
three.js 模型高亮效果实现说明(结合react)
three.js react 实现鼠标移入模型高亮选中效果 使用EffectComposer和其附加的渲染效果Passes(如RenderPass和OutlinePass)来实现高级渲染效果。首先创建EffectComposer实例,并添加RenderPass和OutlinePass,最后在渲染循环中调用…...
入营测评题解
第一题:first 第二题:chengji 打擂台,每个数跟当前最大、最小值比较,维护当前最值即可。 #include<bits/stdc.h> using lllong long; using namespace std;const int N1e610;int n; int x;//1e9, ll最大9e18 ll maxn0,minn…...
制造知识普及(十)-- 常见的工业软件介绍
「 1. ERP」 企业资源计划(enterprise resource planning,ERP)是制造企业的核心管理软件。ERP系统的基本思想是以销定产,协同管控企业的产、供、销、人、财、物等资源,帮助企业按照销售订单,基于产品的制造…...
Windows系统设置网络IPv4和IPv6优先访问级
Windows系统设置网络IPv4和IPv6优先访问级 资源宝整理分享:www.httple.net 在数字化的世界中,我们离不开互联网,而互联网协议(IP协议)则扮演着至关重要的角色。IPv4曾是互联网的主要标准,但随着IP地址枯竭问…...
yolov8 剪枝 - DepGraph
2024年8月5 5000张图片,2个类别。 yolov8n 初始: 185 layers, 3151904 parameters, 31936 gradients, 8.7 GFLOPs 经过三次finetune后: 185 layers, 2327024 parameters, 31936 gradients, 6.6 GFLOPs 经过第四次fintune后: …...
【网络】套接字socket编程预备知识
1.源IP地址和目的IP 计算机网络中的源地址和目的地址是用来标识网络中的不同主机的。 源地址是指发送数据包的主机的地址,而目的地址则是指接收数据包的主机的地址,在数据包传输过程中,每经过一个路中器感交换机,都会根据目的地址…...
【学习笔记】Day 8
写在开头: 最近老板突然提出一个全新的组会主题,是关于 “最近我犯的傻”,其目的在于提供乐子的同时引以为戒。本来我还在愁到底去哪里找干的啥事儿,结果今天直接拉了个大的。什么叫无心插柳柳成荫啊,悲。 一…...
springboot整合libreoffice(两种方式,使用本地和远程的libreoffice);docker中同时部署应用和libreoffice
一、 背景 因为项目中需要使用word转pdf功能,因为转换速度原因,最后选用了libreoffice,原因及部署请参考 linux ubuntu环境安装libreoffice,word转pdf 远程调用的话可选docker部署,请看2.3.1 二、springboot整合libr…...
从入门到精通:大学生编程技能提升全攻略
文章目录 每日一句正能量前言编程语言选择编程语言选择:为新手导航Python:初学者的友好伙伴JavaScript:Web开发的核心Java:企业级应用的经典C:系统编程的基石Ruby:优雅高效的编程Swift:iOS开发的…...
C# .NET Framework的特殊委托
C# .NET Framework的特殊委托 .NET Framework中定义了几种特殊的委托类型,以简化委托的使用。以下是一些常用的特殊委托类型: Predicate<T> 这是一个返回布尔值的委托,接受一个类型为T的参数。常用于定义过滤条件。 using System; …...
C# 判断电脑是否联网
项目中连接webAPI需要判断是否联网,故找到这个方法,不需要引用任何dll,代码复制一下,直接使用。wininet.dll是系统自带的 public void Initial(){try{ if (IsNetworkConnected){SvMaster.Log.WriteInfo("网络…...
爬虫解析代码结构
在设计中加入一个顶层接口是有益的,特别是当您希望实现统一的接口来处理所有类型的排行榜数据时。这样做可以提供更好的灵活性和扩展性,同时保持代码的整洁和易于维护。 设计概述 接口: 定义一个 RankingDataCollector 接口,它定义了所有数…...
day 23 进程间通信—管道
注意事项: 1、如果管道中至少有一个写端: 如果管道中有数据,直接读出 如果管道中没有数据,会阻塞等待直到有数据写入后读出 2、如果管道中没有写端: 如果管道中有数据,直接…...
Python酷库之旅-第三方库Pandas(073)
目录 一、用法精讲 296、pandas.Series.dt.as_unit方法 296-1、语法 296-2、参数 296-3、功能 296-4、返回值 296-5、说明 296-6、用法 296-6-1、数据准备 296-6-2、代码示例 296-6-3、结果输出 297、pandas.Series.dt.days属性 297-1、语法 297-2、参数 297-3、…...
使用easyexcel导出,发生了Exception: could not find acceptable repesentation
报错信息: 原因以及解决方案: 原因是我的代码使用Resp响应返回实体,其实使用EasyExcel导出已经设置了响应编码,导致重复了。 当你通过 HttpServletResponse 的输出流写入文件时,你已经直接控制了响应体。如果此时还尝…...
android display 笔记(五)HWC(Hardware Composer)
HWC 简单来说HWC是用来合成图形和显示图形的,可以把多个图形缓存传给硬件混合渲染器,让硬件混合渲染器执行合成操作,显示图形就是直接将图形缓存显示到屏幕。 android 14 /hardware/interfaces/graphics/composer/2.1/IComposer.hal 19 im…...
【模电笔记】——集成运算放大电路
tips:本章节的笔记已经打包到word文档里啦,建议大家下载文章顶部资源(有时看不到是在审核中,等等就能下载了。手机端下载后里面的插图可能会乱,建议电脑下载,兼容性更好且易于观看),…...
Android Studio Gradle多渠道打包
原理使用Android Studio打一次渠道包,用反编译工具反编译后,修改渠道信息重新编译 准备文件 分渠道配置文件:channel.txt ↓ # 多渠道配置里“统计平台”、“市场名称”、“渠道编号”分别代表什么意思? # 统计平台:…...
什么是DNS缓存?DNS缓存有哪些作用和危害?
在互联网世界的运转机制中,DNS(域名系统)是其中的关键,而DNS缓存则是这一系统的重要环节。它既能加快网站的访问速度,同时也会对网络安全造成影响,因此了解DNS缓存对于网站的日常管理至关重要。 什么是DNS…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...
