MYSQL 主从不一致的原因分析

数据库作为存储数据的组件,数据的一致性一定是要保证的前提,今天给出两个场景来分析数据不一致的原因。

binlog同步模式导致主从不一致

在MYSQL 中主库向从库同步数据是利用binlog记录修改操作,然后将binlog传递给从库进行复制,binlog的格式有3种,

row 在对update,delete,insert语句进行记录时会进行修改的行数据进行记录。row格式的坏处在于比较占用空间,比如更新十万行数据,那么row格式将会把10万数据记录下来。

statement 只会将原始的sql语句记录下来。但是这种格式可能会引起主备不一致。

mixed 是前面两种格式的混合,MYSQL会自己去判断这条sql是不是会造成主备不一致,将引起主备不一致的sql记录成row格式。

statement 为什么会主备不一致?

举一个例子来说明下,statement主备不一致的原因,例如下面的sql

update navigation.t_account set id = uuid();

当你使用 类似uuid或者now这种动态函数时,那么在主库的生成结果将会和从库不同。造成数据的主备不一致。

为什么大多数时候我们还是用row

大多时候,我们还是用row 格式写入binlog,这样带来的好处是便于恢复数据,下面我举例说明下,

  • 当你执行错delete语句,能够通过binlog日志找到删除行的所有字段信息,不过需要注意的是,需要将binlog_row_image 参数设置为FULL,才会记录所有字段信息,如果设置为MINIMAL 则只会记录删除字段信息。

  • 当你执行错update语句,通过binlog记录的修改前后的整行数据,对数据进行恢复。

  • 当你执行错insert语句,能够通过binlog找到插入数据的id,对错误插入的数据进行删除。

所以,为了避免主从不一致,还是选用row 格式记录binblog吧,或者至少还是选用mixed

主备切换导致主从不一致

第二种主从不一致的场景是发生在主备切换时,我先直接说下结论,主备切换方式其实分可靠性优先方式与可用性优先方式。

可靠性优先方式,MYSQL服务可能会存在短暂的不可提供服务的时间段,可用性优先则是保证MYSQL在切换过程中都是可用的。

为了方便,下面我将主主数据库称为master,从数据库称为slave。

可靠性优先方式

1,判断slave是否已经 seconds_behind_master,是否小于5s或更短,seconds_behind_master 代表主从同步延迟的时间,如果小于5s,则继续下一步。

2,修改master的readonly 参数为true, 将master变为只读状态。

3,判断slave的主从同步延迟是否变为0,即seconds_behind_master 等于0,等于0后,继续下一步。

4,修改 slave的 readonly参数改为false,将slave变为可读可写状态。

5,将业务请求转发到slave,原先master,修改为新master的从库。

这个切换过程,数据库是有一段时间不可写的,必须等待slave主从延迟同步变为0以后才行,所以这也是为什么要在seconds_behind_master 在一个较小的值才开始进行主备切换的原因。

可用性优先方式

接着看下保证可用性优先的主备切换方式,在上述主备切换步骤中,我们去掉第三个步骤,也就是不等到主从同步完成就去切换主备。

现在假设现在的binlog为 row格式。表定义为

mysql> CREATE TABLE `t` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `c` int(11) unsigned DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;

insert into t(c) values(1),(2),(3);

业务此时进行插入操作,

insert into t(c) values(4);
insert into t(c) values(5);

当在执行完第一个sql时,进行主备切换,且假设此时备库并没有完成第一条sql的同步。如下图所示,在插入4这条数据时,将slave改为可写,接着业务系统后续的写就往slave写入了5这条数据。注意此时master的4这条数据还没有同步到slave。

接着开始准备更改主备关系,如下图所示,更改关系前,有可能slave才会进行来自master的4这条数据的写入,但是因为slave中已经有id为4的数据了,所以会导致插入失败。

修改slave为master后,插入到之前从库的(4,5)这条数据 会同步到新的slave主机(即旧master),但是这个时候也会因为旧master有id为4的这条数据导致同步失败。主备同步就会自动停止。

可以看到,最后主从数据库中有id等于4这条数据不一样。

所以,可用性优先的主备切换方式是有可能导致主备不一致的。

数据库最重要还是数据的正确性,拿许多业务场景来说,如果数据错乱了,是较难恢复的,但是如果业务失败了,还可以通过重试重新填充数据,怕就怕成功一半,失败一半。所以主备切换的时候尽量还是可靠性优先方式比较好。

文章转载自:蓝胖子的编程梦

原文链接: https://www.cnblogs.com/hobbybear/p/18070737

体验地址: 引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

相关推荐
清水白石00841 分钟前
从一个“支付状态不一致“的bug,看大型分布式系统的“隐藏杀机“
java·数据库·bug
Python私教5 小时前
model中能定义字段声明不存储到数据库吗
数据库·oracle
mqiqe8 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
工业甲酰苯胺8 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
BestandW1shEs8 小时前
谈谈Mysql的常见基础问题
数据库·mysql
重生之Java开发工程师8 小时前
MySQL中的CAST类型转换函数
数据库·sql·mysql
教练、我想打篮球8 小时前
66 mysql 的 表自增长锁
数据库·mysql
Ljw...8 小时前
表的操作(MySQL)
数据库·mysql·表的操作
哥谭居民00018 小时前
MySQL的权限管理机制--授权表
数据库