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…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...

Appium下载安装配置保姆教程(图文详解)
目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...