首页 > 数据库 >Mysql与Redis如何保证数据的一致性?

Mysql与Redis如何保证数据的一致性?

时间:2022-11-28 13:22:47浏览次数:53  
标签:删除 数据 Mysql Redis 更新 MySQL 一致性 保证数据

问题分析:

当MySQL中的数据发生更新时,就面临一个问题,如何确保MySQL与Redis数据的一致性,我们有两个选择:

  1. 先更新MySQL,后删除(或更新)Redis
  2. 先删除(或更新)Redis,后更新MySQL

但是不管使用其中哪种方式,都存在两个可能的问题:

  1. 由于第一步与第二步并不是原子的,中间会存在较短的时间间隔,如果间隔时间内有请求到达,就可能会访问到不一致的数据。
  2. 可能存在做完第一步,第二步还没来得及做,系统就发生异常的情况;这就会导致MySQL与Redis的数据不一致。

解决方案:

1、最终一致性:容忍数据短时不一致,最终达到一致即可

可以采用先删除Redis,后更新MySQL的方式来保证最终一致性。

  1. 删除Redis
  2. 在这时有请求到达,读取MySQL内容并写入Redis(此时写入的数据是旧的)
  3. 更新MySQL
  4. 删除Redis(再执行一次删除Redis,就可以确保Redis中的内容为最新数据)
    image
    但是上述的保证事务提交完以后再进行删除缓存还有一个问题,就是如果你使用的是 Mysql 的读写分离的架构的话,那么其实主从同步之间也会有时间差。
    image

此时来了两个请求,请求 A(更新操作) 和请求 B(查询操作)

  1. 请求 A 更新操作,删除了 Redis
  2. 请求主库进行更新操作,主库与从库进行同步数据的操作
  3. 请 B 查询操作,发现 Redis 中没有数据
  4. 去从库中拿去数据
  5. 此时同步数据还未完成,拿到的数据是旧数据

此时的解决办法就是如果是对 Redis 进行填充数据的查询数据库操作,那么就强制将其指向主库进行查询。
image

2、强一致性:数据实时保持一致

先更新数据库,后删除缓存
问题:更新数据库成功了,但是在删除缓存的阶段出错了没有删除成功,那么此时再读取缓存的时候每次都是错误的数据了。

此时解决方案就是利用消息队列进行删除的补偿。
image
具体的业务逻辑用语言描述如下:

  1. 请求 A 先对数据库进行更新操作
  2. 在对 Redis 进行删除操作的时候发现报错,删除失败
  3. 此时将Redis 的 key 作为消息体发送到消息队列中
  4. 系统接收到消息队列发送的消息后再次对 Redis 进行删除操作

但是这个方案会有一个缺点就是会对业务代码造成大量的侵入,深深的耦合在一起。
所以这时会有一个优化的方案,引入第三方服务,订阅(监听)MySQL master节点的binlog,当binlog产生时,按binlog顺序更新Redis数据即可。比如阿里开源的canal组件。
image

个人认为这里实现的【强一致性】也并不是真的【实时一致】,而是【近实时】,因为读取binlog并在Redis上执行更新,依然需要时间,只是这个时间会比较短而已。

标签:删除,数据,Mysql,Redis,更新,MySQL,一致性,保证数据
From: https://www.cnblogs.com/zhaojinhui/p/16931940.html

相关文章

  • redisOject 和 底层数据结构对应 学习笔记
    笔记摘抄自https://pdai.tech/md/db/nosql-redis/db-redis-data-type-enc.htmlredisObject查看编码命令setk11objectencodingk1setk2helloobjectencoding......
  • python3.7安装mysqlclient失败问题
    问题直接使用pipinstall安装mysqlclient最新版本2.1.1失败了,提示“Failedbuildingwheelformysqlclient”解决步骤:换wheel方式安装,去pypi官网准备下载文件,突然发......
  • ThinkPHP6 使用原生mysql表达式
    1if(!empty($param)){2$where[]=['','exp',Db::raw("FIND_IN_SET(".$param.",mysqlfield)")];3}使用这种查询表达式,注意几点:1.数组......
  • JavaWeb-MySql高级
    JavaWeb-MySql高级1,约束1.1概念约束是作用于表中列上的规则,用于限制加入表的数据例如:我们可以给id列加约束,让其值不能重复,不能为null值。约束的存在保证了数据......
  • MySQL锁:InnoDB行锁需要避免的坑
    前言换了工作之后,接近半年没有发博客了(一直加班),emmmm.....今天好不容易有时间,记录下工作中遇到的一些问题,接下来应该重拾知识点了。因为新公司工作中MySQL库经常出现......
  • mysql删除所有表中数据
    建立存储过程dropprocedureifexistsdel_all_tb;delimiter$$createproceduredel_all_tb(dbchar(20))begindeclaredoneintdefault0;declaretbc......
  • mysql只更改字段年月日时间,时分秒不变
    数据库导入数据,年月日出现问题了,如图所示,只能通过sql更改年月日。想修改一列时间,将其年月日修改为自己想要的时间执行如下sql:UPDATEyieldsetdataTime=ADDTIME(DAT......
  • Mysql 直接拷贝数据库文件导致表不显示的问题
    前言:最近有一个需求,需要迁移数据库中的其中一个库,需要迁移的那个数据库占用了700多G的空间,所以采用直接拷贝数据库文件的方式,拷贝到另一台服务器后发现表不显示,记录本次问......
  • mysql 数据库管理
    一、常用的数据类型二、数据库管理2.1创建数据库和表-create2.2删除数据库和表-drop  一、常用的数据类型类型解释举例int整型......
  • MySQL对时间戳的格式化
    时间转时间戳selectunix_timestamp('2022-02-2222:22:22');时间戳转时间selectfrom_unixtime(1645539742);格式化SELECTfrom_unixtime(1645539742,'%Y-%m-%d%H......