Redis与MySQL如何保证数据一致性
Redis与MySQL如何保证数据一致性
简单来说
该场景主要发生在读写并发进行时,才会发生数据不一致。
主要流程就是要么先操作缓存,要么先操作Redis,操作也分修改和删除。
一般修改要执行一系列业务代码,所以一般直接删除成本较低。
如果我们先删除Redis中数据,就会出现修改数据库数据时,其他线程读取到Redis为空,从数据库查,并写入Redis中,但这就是脏数据了,所以可以采用延迟双删策略,就是再删除一次,需要延迟的原因是因为在其他线程查时给Redis设置旧数据时,不延迟,就会覆盖新数据。(所以一般都要根据自己的业务逻辑评估一下大概时间。)如果说需要在这个阶段也需要保证数据一致性,那就只能上锁,保证强一致性,因为Redis和数据库是两个服务,只能通过加锁保证原子性,而这就影响了系统吞吐量(就违背了使用Redis提高吞吐量,也就是AP和CP不能同时满足的问题),所以一般都是保证最终一致性。
如果先修改数据库,同样会有数据不一致情况,在修改数据库处理时,其他线程也会读取旧数据,处理完了数据库就会删除缓存,保证了数据最终一致性,(所以比较推荐这种操作)
但是上述两种都会有删除Redis失败的情况,可以选择异步发送消息到MQ,线程监听MQ执行重试删除。
但这里的MQ代码过于耦合,需要解耦的话,就可以将他们提取出来,使用阿里的一款开源框架canal主要用途是基于MySQL数据库增量日志解析,提供增量数据订阅和消费Canal提供了各种语言的客户端,当Canal监听到binlog变化时,会通知Canal的客户端,过程也就是执行失败后,异步发送消息到MQ,Canal客户端监听到MQ消息执行重试
详细来说
1、引入
Redis 用来实现应用和数据库之间读操作的缓存层,主要目的是减少数据库 IO,还可以提升数据的 IO 性能。
当应用程序需要去读取某个数据的时候,首先会先尝试去 Redis 里面加载,如果命中就直接返回。如果没有命中,就从数据库查询,查询到数据后再把这个数据缓存到 Redis 里面。
这样一个架构中,会出现一个问题,就是一份数据,同时保存在数据库和 Redis 里面,当数据发生变化的时候,需要同时更新 Redis 和 Mysql,由于更新是有先后顺序的,并且它不像 Mysql中的多表事务操作,可以满足 ACID 特性。所以就会出现数据一致性问题。

2、同步策略
想要保证缓存与数据库的双写一致,一共有4种方式,即4种同步策略:
先更新缓存,再更新数据库; 先更新数据库,再更新缓存; 先删除缓存,再更新数据库; 先更新数据库,再删除缓存。 从这4种同步策略中,我们需要作出比较的是:
更新缓存与删除缓存哪种方式更合适?应该先操作数据库还是先操作缓存?
一般直接删除,因为缓存的更新成本更高 (因为你写入数据库的值,很多情况并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值无疑是浪费性能的。显然,删除缓存更为适合。)删除缓存操作简单,副作用只是增加了一次 chache miss,建议大家使用该策略。
一般先操作数据库,因为更方便保证最终一致性,先往下看
3、操作理解
先操作缓存

如果我们先删除Redis中数据,就会出现修改数据库数据时,其他线程读取到Redis为空,从数据库查,并写入Redis中,但这就是脏数据了,所以可以采用延迟双删策略,就是再删除一次,需要延迟的原因是因为在其他线程查时给Redis设置旧数据时,不延迟,就会覆盖新数据。(所以一般都要根据自己的业务逻辑评估一下大概时间。)如果说需要在这个阶段也需要保证数据一致性,那就只能上锁,保证强一致性,因为Redis和数据库是两个服务,只能通过加锁保证原子性,而这就影响了系统吞吐量(就违背了使用Redis提高吞吐量,也就是AP和CP不能同时满足的问题),所以一般都是保证最终一致性。
先操作数据库

如果先修改数据库,同样会有数据不一致情况,在修改数据库处理时,其他线程也会读取旧数据,处理完了数据库就会删除缓存,保证了数据最终一致性,(所以比较推荐这种操作)
4、解决
一般使用延迟双删和删除重试机制
延迟双删
一个读线程发现缓存中没有对应的数据,去查库,在查询完毕准备更新缓存期间,另一个写线程完成了写库以及对缓存的删除(此时数据库中的数据是新数据,而读线程将缓存更新为旧数据),一般情况下,这种事件的发生概率很低,但是使用延迟双删可以规避掉这种问题,进一步提高数据的一致性,但缺点就是性能会有所下降
那具体的超时时间要根据你具体的业务来定,一般设置几秒足够了
队列+重试机制
上述情况都会有删除Redis失败的情况,可以使用重试机制
比如重试三次,三次都失败则记录日志到数据库并发送警告让人工介入在高并发的场景下,重试最好使用异步方式,比如发送消息到 mq 中间件,实现异步解耦
也就是选择异步发送消息到MQ,线程监听MQ执行重试删除。

Cannal解耦
但这里的MQ代码过于耦合,需要解耦的话,就可以将他们提取出来,使用阿里的一款开源框架canal主要用途是基于MySQL数据库增量日志解析,提供增量数据订阅和消费Canal提供了各种语言的客户端,当Canal监听到binlog变化时,会通知Canal的客户端,过程也就是执行失败后,异步发送消息到MQ,Canal客户端监听到MQ消息执行重试
通过该框架可以对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。 MQ消息中间可以采用RocketMQ来实现推送

相关文章:
Redis与MySQL如何保证数据一致性
Redis与MySQL如何保证数据一致性 简单来说 该场景主要发生在读写并发进行时,才会发生数据不一致。 主要流程就是要么先操作缓存,要么先操作Redis,操作也分修改和删除。 一般修改要执行一系列业务代码,所以一般直接删除成本较低…...
基于微信小程序的教室预约系统+LW示例参考
1.项目介绍 功能模块:管理员(学生管理、教师管理、申请管理、设备管理、报修管理等)、普通用户/学生(注册登录、申请预约、退订、报修等)技术选型:SSM、JSP、uniapp等测试环境:idea2024&#x…...
Linux 安装 Git 服务器
一、安装 Git 1. 在 CentOS/RHEL 中使用以下命令: sudo yum update -y # 或者 sudo dnf update -y (在较新的系统中) sudo yum install git -y验证安装:git --version 2. 配置 Git 用户 git config --global user.name "Your Name" git co…...
总结:Yarn资源管理
一、介绍 本文梳理下Yarn的资源分配计算逻辑。 二、配置 - 资源限制 1、配置NodeManager可分配的资源池的总量 <property><name>yarn.nodemanager.resource.memory-mb</name><value>4096</value> </property> 作用对象:节点管理器(No…...
Python学习34天
import random class Game: peo0 rob0 # # def __init__(self,peo,rob): # self.peopeo # self.robrob def Play(self): """ 石头剪刀布游戏,0代表石头,1代见到,2代表石头 …...
深入浅出 WebSocket:构建实时数据大屏的高级实践
简介 请参考下方,学习入门操作 基于 Flask 和 Socket.IO 的 WebSocket 实时数据更新实现 在当今数字化时代,实时性是衡量互联网应用的重要指标之一。无论是股票交易、在线游戏,还是实时监控大屏,WebSocket 已成为实现高效、双向…...
三开关VUE组件
一、使用效果 <template><QqThreeSwitch v-model"value" /><!-- <SqThreeSwitch v-model"value" :options"[test1, test2, test3]"><template #left-action><div style"display: flex"><IconMoon…...
SpringCloud+SpringCloudAlibaba学习笔记
SpringCloud 服务注册中心 eureka ap 高可用 分布式容错 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency><groupId…...
牛客小白月赛105(A~E)
文章目录 A lz的吃饭问题思路code B lz的数字问题思路code C lz的蛋挞问题思路code D lz的染色问题思路code E lz的括号问题思路code 总结 牛客小白月赛105 A lz的吃饭问题 思路 签到题,比较大小即可 code void solve(){int a,b,c,d;cin >> a >> b…...
OSPF协议整理
OSPF(Open Shortest Path First)即开放式最短路径优先协议,是一种广泛应用于大型网络中的链路状态路由协议。 OSPF 的基本概念 OSPF 是基于链路状态算法的内部网关协议(IGP),用于在一个自治系统ÿ…...
Java中的多线程
文章目录 Java中的多线程一、引言二、多线程的创建和启动1、继承Thread类2、实现Runnable接口 三、线程的常用方法1、currentThread()和getName()2、sleep()和yield()3、join() 四、线程优先级五、使用示例六、总结 Java中的多线程 一、引言 在Java中,多线程编程是…...
什么是聚簇索引、非聚簇索引、回表查询
其实聚集索引也叫聚簇索引,二级索引也叫非聚簇索引,大家不要认为这是不同的两个知识点。 定义 先看一下数据库的索引介绍。 聚簇索引 1. 如果存在主键(一般都存在),主键索引就是聚簇索引。 2. 如果不存在,…...
探索 Spring 框架核心组件:构建强大 Java 应用的基石
Spring框架作为Java企业级开发的首选框架之一,其强大的功能和灵活的架构深受开发者喜爱。Spring框架的核心组件共同构建了一个高效、可扩展的应用程序开发平台。本文将深入探讨Spring框架的核心组件,揭示它们如何在Spring框架中发挥关键作用。 一、Bean…...
Android 13 Aosp 默认允许应用动态权限
图库 frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java 修改 public void grantDefaultPermissions(int userId) {DelayingPackageManagerCache pm new DelayingPackageManagerCache();grantPermissionsToSysCompon…...
【C++知识总结1】c++第一篇,简单了解一下命名空间是什么
一、C的由来 C语言是一种结构化和模块化的编程语言,它对于处理较小规模的程序非常适用。然而,当面临需要高度抽象和建模的复杂问题,以及规模较大的程序时,C语言就显得不那么合适了。为了应对这种挑战,并在解决软件危机…...
从0开始深度学习(32)——循环神经网络的从零开始实现
本章将从零开始,基于循环神经网络实现字符级语言模型(不是单词级) 首先我们把从0开始深度学习(30)——语言模型和数据集中的load_corpus_time_machine()函数进行引用,用于导入数据: train_iter…...
GitLab使用操作v1.0
1.前置条件 Gitlab 项目地址:http://******/req Gitlab账户信息:例如 001/******自己的分支名称:例如 001-master(注:master只有项目创建者有权限更新,我们只能更新自己分支,然后创建合并请求&…...
cuda conda yolov11 环境搭建
优雅的 yolo v11 标注工具 AutoLabel Conda环境直接识别训练 nvidia-smi 检查CUDA版本 下载nvidia cudnn对应的版本 将cuDNN压缩包内对应的文件复制到本地bin、include、lib的文件夹中 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.6 miniConda快速开始-安装 执行…...
解决SpringBoot连接Websocket报:请求路径 404 No static resource websocket.
问题发现 最近在工作中用到了WebSocket进行前后端的消息通信,后端代码编写完后,测试一下是否连接成功,发现报No static resource websocket.,看这个错貌似将接口变成了静态资源来访问了,第一时间觉得是端点没有注册成…...
element-plus的组件数据配置化封装 - table
目录 一、封装的table、table-column组件以及相关ts类型的定义 1、ATable组件的封装 - index.ts 2、ATableColumn组件的封装 - ATableColumn.ts 3、ATable、ATableColumn类型 - interface.ts 二、ATable、ATableColumn组件的使用 三、相关属性、方法的使用以及相关说明 1. C…...
【译】《心悟内核:先懂设计,再读代码》—1、内核并非进程,而是整个系统本身
作者:Moon Hee Lee 原文: The Kernel in the Mind 心悟内核:先懂设计,再读代码——内核并非进程,而是整个系统本身Linux 内核既不是普通进程、守护进程,也不是应用程序。它是一套常驻内存的高特权运行环境,…...
泛微OA ecology 9实战:手把手教你写一个能取表单数据的Java自定义接口
泛微OA Ecology 9深度开发:构建高效表单数据交互的Java接口实践 在当今企业数字化转型浪潮中,办公自动化系统(OA)作为核心支撑平台,其灵活性和扩展性直接影响着企业运营效率。泛微OA Ecology 9作为国内领先的协同办公平台,提供了丰…...
Azure AI实战:从Demo到生产级智能应用架构全解析
1. 项目概述与核心价值最近在探索Azure AI服务时,我偶然发现了一个名为“Azure-AIGEN-demos”的GitHub仓库。这个项目由开发者retkowsky维护,乍一看名字,你可能会觉得它又是一个普通的Azure AI示例代码合集。但当我真正深入进去,花…...
Shell脚本工程化:great.sh框架解决运维脚本可维护性难题
1. 项目概述:一个被低估的Shell脚本构建框架如果你和我一样,常年混迹在运维、DevOps或者后端开发领域,那么对Shell脚本的感情一定是复杂的。一方面,它是我们最趁手的“瑞士军刀”,从服务器初始化、日志分析到自动化部署…...
GPU工作负载分析与系统优化实践
1. GPU工作负载分析:从硬件计数器到系统优化在当今高性能计算(HPC)领域,GPU加速集群和超级计算机已成为不可或缺的计算资源。随着GPU硬件性能的不断提升,其暴露的硬件计数器也日益丰富,为深入理解GPU工作负…...
Linux服务器远程桌面实战:xrdp配置与Windows无缝连接指南
1. 为什么需要xrdp远程桌面? 刚接触Linux服务器的朋友经常会问我一个问题:"能不能像Windows那样直接用远程桌面连接?"说实话,我第一次管理Linux服务器时也有同样的困惑。毕竟对于习惯了Windows图形界面的用户来说&#…...
LLM长文本处理实战:模块化分割策略与向量化预处理指南
1. 项目概述:一个为LLM打造的文本处理中心如果你和我一样,经常和大型语言模型打交道,无论是用它来总结文档、分析代码,还是处理客服对话,那你肯定遇到过这个痛点:喂给模型的文本太长了怎么办?模…...
基于Arduino Pro Micro的薄膜键盘矩阵改造:DIY低成本模拟飞行外设
1. 项目概述:为Falcon BMS打造一款经济型多功能按键面板如果你是一名《Falcon BMS》的飞行模拟爱好者,同时又对硬件DIY抱有热情,那么你很可能和我一样,对市面上那些动辄数百甚至上千元的专业模拟飞行外设感到望而却步。尤其是像F-…...
HDiffPatch实际应用案例:APK文件差异化和Android应用商店优化
HDiffPatch实际应用案例:APK文件差异化和Android应用商店优化 【免费下载链接】HDiffPatch a C\C library and command-line tools for Diff & Patch between binary files or directories(folder); cross-platform; runs fast; create small delta/differentia…...
告别繁琐配置:Jprotobuf注解驱动序列化实战(新手友好)
1. 为什么选择Jprotobuf注解方案 如果你正在用Java开发需要频繁序列化数据的应用,比如缓存系统、微服务通信或者游戏服务器,肯定遇到过这样的纠结:用JSON虽然方便但性能差体积大,用Protobuf性能好但配置太麻烦。我去年做电商订单系…...
