当前位置: 首页 > news >正文

MySQL 与 Redis 数据一致性 2

  • 1. 强一致还是最终一致?
  • 2. 先写 MySQL 还是先写Redis?
      • case 1
  • 3. 缓存(Redis)更新还是清除?
    • 更新策略
      • 更新策略会有数据不一致问题?
      • 数据不一致的概率与影响
      • 如果使用监听binlog更新数据还会出现数据不一致问题?
        • binlog的消费问题
      • 使用消息队列行不行?
      • 其他方案
      • 总结: 数据不一致的处理方案
    • 清除策略
      • 解决缓存击穿问题的方案
          • 分布式锁
          • 使用更新策略
    • 更新策略与清除策略的使用场景
        • 更新策略
        • 删除策略
  • 4. 缓存(Redis)写的方式有哪些?
      • 同步写
      • 异步写
        • 协程写
        • 监听binlog写
      • 其他方案
  • 总结
      • 其他保证:

1. 强一致还是最终一致?

  • Redis的定位是缓存,缓存的主要目的是为了减轻MySQL(DB层)的请求压力,并且快速响应

  • 所以缓存一定要保持高性能,但是强一致性会严重破坏高性能的特性,所以一般是采用最终一致性的方案.

  • 你能找到的市面上大部分的解决方案都是最终一致性的

2. 先写 MySQL 还是先写Redis?

先写 MySQL

  • 原则: 谁保存全量持久化数据先更新谁

为什么需要先写 MySQL?

  • 避免MySQL数据覆盖,丢失更新;(造成永久性错误)

  • 因为并发情况下先写 Redis,无法保证 MySQL 写的时候是顺序的

case 1

假设有两个连续的更改视频标题的请求,

  • 请求 1改为 A;
  • 请求 2改为 B

先写 Redis先改成 A,然后改成 B(Redis 是单线程的,请求将顺序执行)

这时候请求 1 的线程处理比较慢(或者阻塞了一下)

这时候请求 2 先更新了持久化全量数据(MySQL) 中记录:改为 B

然后请求 1 才开始更改MySQL 中的数据:改为 A

这时候 MySQL 的数据是错的,并且重启也无法恢复的错误

如果先更新 Redis 会造成无法修复的数据不一致(MySQL 数据是错误的)

结论: 先做 MySQL 的更新,再更新 Redis

3. 缓存(Redis)更新还是清除?

原则: 必须避免缓存击穿(大量访问打到MySQL 将 MySQL 打爆)

  • 简单理解就是如何 MySQL 崩溃了,整个服务就直接炸了

更新策略

  • 优势: 可以有效避免缓存击穿问题
  • 缺点: 可能存在数据不一致问题

更新策略会有数据不一致问题?

假设有两个连续的更新视频标题的请求

  • 请求 1改为 A;
  • 请求 2改为 B

先更新 MySQL,先改成 A,然后改成 B

这时候请求 1 的线程处理比较慢(或者阻塞了一下)

这时候请求 2 先更新了 缓存数据( Redis) 中 的记录

然后请求 1 才开始更改 Redis 中的数据

这时候Redis 的数据是错误的,会导致后面查询的时候全部查询到错误的数据(只能重新加载 MySQL 数据到 Redis 才能恢复)

数据不一致的概率与影响

  • 概率低

    • 一般同一条数据更新会做限制的,比如改名的接口会限制一分钟只能请求一次,甚至有些改名称限制更长
    • 一个用户只能在一个设备上面进行登录,所以很难同时请求多次
    • 简单来讲就是很难出现并发的场景
  • 影响有限

    • 缓存的数据都是有过期时间的,就算有一个黑客巧妙的绕开了前面的限制,还有过期时间兜底,数据到了过期时间会重新查询 MySQL 的最新数据并更新到 Redis(最终一致)

如果使用监听binlog更新数据还会出现数据不一致问题?

单独开一个服务监听数据库 binlog 日志更新缓存可以有效避免数据不一致的问题

  • 首先产生不一致的原因是更新缓存的顺序无法保证,因为有的请求执行快,有的请求执行慢,这个无法保证,所以有可能造成覆盖的问题

  • 但是 binlog 是有序的,按照事务提交的顺序进行追加的,所以使用 binlog 更新缓存(Redis)就是按照事务提交的顺序进行更新,就不会出现数据不一致的问题

binlog的消费问题
  • binlog要顺序消费就需要使用单线程的模型,这样其实性能并不是很好,但是我们可以使用聚合多次更改,同时做批量提交,可以极大的优化单线程消费的性能
  • 如果是做多线程消费,那么就会有消费顺序的问题.有可能产生数据覆盖的问题(旧数据覆盖新数据(就是上面改名的case)

使用消息队列行不行?

不行

还是原来的逻辑后到的可能先入队,先到的可能后入队(先到的线程阻塞了一下)

  • 消息队列主要能保证数据丢失,并且有重试机制保证更新成功
    (这些其实对于缓存 Redis 来讲都可以接受,因为有过期时间兜底,实现最终一致)

其他方案

分布式锁解决数据不一致问题,但是一般不会使用,因为破坏了Redis 的高性能

总结: 数据不一致的处理方案

  1. 不处理: 一般是低概率事件并且有过期时间兜底,最终一致性保障,不需要因为一个低概率事件去配置复杂又消耗性能的方案
  2. 读取 binlog 更新: 使用 binlog 的有序性解决 Redis 更新执行顺序的问题
  3. 分布式锁(不推荐)

清除策略

  • 优势: 操作简单,内存又好(避免不使用的数据加到 Redis)
  • 缺点: 缓存击穿问题

清除策略有非常大的缓存击穿问题,可能造成 MySQL 被打爆,这是不能接受的

解决缓存击穿问题的方案

分布式锁

当未命中缓存就加分布式锁(使用 lua 脚本)避免大量请求打到 MySQL 导致服务崩溃

使用更新策略

更新策略与清除策略的使用场景

更新策略
  • 抢红包这种高实时性,高并发写的业务(可以预测出一定会再端时间有大量并发读写的请求)
删除策略
  • 适用于更新视频名称这种更新频率比较低的业务(无法预测数据是否热,并且可以接受短时间的延迟不一致(刷新后还是会最终一致))

4. 缓存(Redis)写的方式有哪些?

同步写

  • 优点: 实现简单
  • 缺点: 会加长处理时间(性能低)

伪代码:

// 更新数据库
err := db.Update(data).Error()
if err != nil{return
}// MySQL更新成功再更新 Redis
redis.Update(key,data)//或者使用删除redis.Delete(key)

异步写

协程写
  • 优势: 实现简单
  • 缺点: 开协程有一点点消耗 (8k),增加调度开销

伪代码

// 更新数据库
err := db.Update(data).Error()
if err != nil{return
}// 异步更新 Redis
go redis.Update(key,data)//或者使用删除redis.Delete(key)
监听binlog写

更新接口

// 只做更新数据库操作
err := db.Update(data).Error()
if err != nil{return
}

Redis 更新服务

for{//监听 binlog 日志binlog<-binlogChan//写 Redisredis.Update(binlog["key"],binlog["data"])//或者使用删除redis.Delete(binlog["key"])	
}

其他方案

  1. 消息队列
    优势: 数据丢失,但是对于缓存来讲数据丢失是可以接受的,最终还是会报错了数据一致性(有过期时间兜底)

总结

  • 对于可预见性的热数据,并且并发读写高的数据一般使用监听 binlog +更新缓存 Redis 数据的方式

    • case: 抢红包
  • 对于不可预见热key 并且更新频率低,容忍延迟刷新数据生效的业务使用异步协程+删除 Redis 缓存数据的方案

    • case: 更新视频的名称等

其他保证:

  • 重试与告警: 当写 Redis 失效的时候,再保证幂等(做计算类更新一定要保证幂等再重试,使用 lua)的情况下进行重试

    • 如果超过设定的最大重试次数依旧没有成功,应当立即告警,记录,限流,降级,熔断;并进行抢修
  • 击穿预防: 使用分布式锁限制热key 打到 MySQL 的 请求的数量,避免缓存击穿.

相关文章:

MySQL 与 Redis 数据一致性 2

1. 强一致还是最终一致?2. 先写 MySQL 还是先写Redis?case 1 3. 缓存(Redis)更新还是清除?更新策略更新策略会有数据不一致问题?数据不一致的概率与影响如果使用监听binlog更新数据还会出现数据不一致问题?binlog的消费问题 使用消息队列行不行?其他方案总结: 数据不一致…...

MySQL程序之:使用类似URI的字符串或键值对连接到服务器

本节介绍使用类似URI的连接字符串或键值对来指定如何为MySQLShell等客户端建立到MySQL服务器的连接。 以下MySQL客户端支持使用类似URI的连接字符串或键值对连接到MySQL服务器&#xff1a; MySQL Shell实现X DevAPI的MySQL连接器 本节记录了所有有效的类似URI的字符串和键值…...

Docker私有仓库管理工具Registry

Docker私有仓库管理工具Registry 1 介绍 Registry是私有Docker仓库管理工具&#xff0c;Registry没有可视化管理页面和完备的管理策略。可借助Harbor、docker-registry-browser完成可视化和管理。Harbor是由VMware开发的企业级Docker registry服务。docker-registry-browser是…...

若依前后端分离项目部署(使用docker)

文章目录 一、搭建后端1.1 搭建流程&#xff1a;1.2 后端零件:1.2.1 mysql容器创建&#xff1a;1.2.2 redis容器创建&#xff1a;1.2.3 Dockerfile内容&#xff1a;1.2.4 构建项目镜像&#xff1a;1.2.5 创建后端容器&#xff1a; 二、前端搭建&#xff1a;2.1 搭建流程&#x…...

Unity2021.3.13崩溃的一种情况

如果出现如下的报错&#xff0c;可能是软件冲突的原因。自己的原因是使用f.lux这款软件似乎和Unity相互冲突&#xff0c;出现下面报错。 错误信息如上图...

Temp123

MapDB&#xff1a;的持久化机制&#xff0c;以及源码分析和摘取 1、spark streaming--struct streaming 基于 时间间隔 攒批 2、kafka-connect-hdfs 控制 flush.size 和 interval.ms控制 攒批 - 完全自研 攒批机制 - 使用 embeded 版 https://lxblog.com/qianwen/share?shar…...

春秋杯-WEB

SSTI 可以看到主页那里有个登录测试之后为ssti {{4*4}} fenjing梭哈即可得到payload {{((g.pop.__globals__.__builtins__.__import__(os)).popen(cat flag)).read()}}file_copy 看到题目名字为file_copy&#xff0c; 当输入路径时会返回目标文件的大小&#xff0c; 通…...

JavaEE:多线程初阶

JavaEE&#xff1a;多线程初阶 一、线程的原理和进程与线程之间的关系1. 线程的原理线程的基本概念线程的生命周期线程的调度线程的并发与并行 2. 进程与线程的关系进程&#xff08;Process&#xff09;线程与进程的关系进程和线程的对比线程的优势线程的缺点 3. 总结 二、多线…...

Linux之文件系统前世今生(一)

Linux在线1 Linux在线2 一、 基本概念 1.1 块&#xff08;Block&#xff09; 在计算机存储之图解机械硬盘这篇文章中我们提到过&#xff0c;磁盘读写的最小单位是扇区&#xff0c;也就是 512 Byte&#xff1b;很明显&#xff0c;每次读写的效率非常低。 为了提高IO效率&…...

当设置dialog中有el-table时,并设置el-table区域的滚动,看到el-table中多了一条横线

问题&#xff1a;当设置dialog中有el-table时&#xff0c;并设置el-table区域的滚动&#xff0c;看到el-table中多了一条横线&#xff1b; 原因&#xff1a;el-table有一个before的伪元素作为表格的下边框下&#xff0c;初始的时候已设置&#xff0c;在滚动的时候并没有重新设置…...

Windows远程桌面网关出现重大漏洞

微软披露了其Windows远程桌面网关&#xff08;RD Gateway&#xff09;中的一个重大漏洞&#xff0c;该漏洞可能允许攻击者利用竞争条件&#xff0c;导致拒绝服务&#xff08;DoS&#xff09;攻击。该漏洞被标识为CVE-2025-21225&#xff0c;已在2025年1月的补丁星期二更新中得到…...

vue 前端优化性能优化方法

1.列表使用唯一 key v-for"item in activeList" :key"item.id"原因是不使用 key 或者列表的 index 作为 key 的时候&#xff0c;每个元素对应的位置关系都是 index&#xff0c;直接导致我们插入的元素到后面的全部元素&#xff0c;对应的位置关系都发生了变…...

docker-compose部署kafka 3.3.1 kraft

一、服务器&#xff1a; 节点1:10.1.1.165 节点2:10.1.1.164 节点3:10.1.1.169二、添加环境地址解析 vim /etc/hosts kafka1 10.1.1.165 kafka2 10.1.1.164 kafka3 10.1.1.169三、节点配置 节点1 version: "3" services:kafka1:image: bitnami/kafka:3.3.1contain…...

【Python】第二弹---深入理解编程基础:从常量、变量到注释的全面解析

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】【Python】 目录 1、常量和表达式 2、变量和类型 2.1、变量是什么 2.2、变量的语法 2.3、变量的类型 2.4、动态类型特…...

[BrainShadow-V1] VR头戴设备统计报告

Brain-Shadow-V1 EventVR headsetsReported byXiao enDate2025/01/15Version1.0 HTC Vive Pro 2 Pro HTC Vive Pro 2 是一款高端虚拟现实头显&#xff0c;配备双 2.5K 显示屏&#xff0c;组合分辨率达到 48962448&#xff0c;提供 120 的视场角和 120Hz 的刷新率。该设备支持…...

跨境电商使用云手机用来做什么呢?

随着跨境电商的发展&#xff0c;越来越多的卖家开始尝试使用云手机来协助他们的业务&#xff0c;这是因为云手机具有许多优势。那么&#xff0c;具体来说&#xff0c;跨境电商使用云手机可以做哪些事情呢&#xff1f; &#xff08;一&#xff09;实现多账号登录和管理 跨境电商…...

DAY23 使用具有通用性的队列

1.初始化数组 //Initialize arrays.int tempLength getNumNodes();valuesArray new char[tempLength];indicesArray new int[tempLength];int i 0;2.初始化队列 创建了一个名为tempQueue的CircleObjectQueue对象&#xff0c;即一个循环对象队列。 将当前对象&#xff08;即…...

汽车网络信息安全-ISO/SAE 21434解析(上)

目录 概述 第四章-概述 1. 研究对象和范围 2. 风险管理 第五章-组织级网络安全管理 1. 网络安全治理&#xff08;cybersecurity governance&#xff09; 2. 网络安全文化&#xff08;cybersecurity culture) 3. 信息共享&#xff08;Information Sharing) 4. 管理体系…...

通用查询类接口开发的另类思路

文章目录 一、需求概述二、开发方式1、传统开发方式2、将接口视为资源文件1.&#xff09;springmvc工程2.&#xff09;springboot工程3.&#xff09;nginx代理 三、接口数据如何更新1、原始数据文件生成接口数据1.&#xff09;定义启动类2.&#xff09;启动监听3.&#xff09;文…...

uc/os-II 原理及应用(八) 系统裁减以及移植到51单片机-下

现在说明几个重要的点&#xff0c; OSStartHighRdy 的作用就是把任务栈复制到系统栈上面&#xff0c;再利用RET的时候会从系统栈上到一个地址放到PC寄存器上来实现任务运行。OSCtxSw是任务切换&#xff0c;把系统栈全部备份到当前任务栈映射上&#xff0c;然后改OSTCBCur,调用…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...