MySQL主从复制技术应用非常广泛,M-S复制架构、keepalived+M-M复制架构、MHA等高可用架构都基于MySQL主从复制技术。但因主从复制是基于binlog的逻辑复制,实际应中,可能会因为各种原因出现主从数据不一致的情况,关系数据则无小事,因此我们需要定期或不定期地开展主从复制数据一致性的校验和修复工作。那么对于mysql主从数据不一致的情况,应该怎样修复呢?不止一次听到说只需要从主库重新导入备库就可以了,咋一听似乎没毛病,但细思极恐,下面我们来探讨这些问题。


[ 错误操作 ]

Master节点
mysqldump -uxxx -p  test aa--set-gtid-purged=OFF  > aa.sql
Slave节点
Source aa.sql
Start slave;

很多人处理数据不一致时采用以上操作,甚至有些专业MySQLDBA也是采取如此操作,如果数据完全静态,这样操作没有问题。但数据往往都是动态变化的,那如何确保导出导入和salve故障点的时刻的一致性呢?“现在mysql都是基于GTID的复制,mysql自己会找去从哪里开始复制”有人这样解释,但是GTID是全局的,在运行的复制架构中,无法自动针对某一张表去挑选数据进行复制应用。


[ 错误分析 ]

下面就上面的操作进行详细分析,以下数据表特指复制中存在数据差异的数据表:

mysql8主从恢复 mysql主从修复_mysql自动停止运行

  • T1时刻发现复制异常
  • T2时刻在master导出数据表
  • T3时刻在slave导入数据表并启动复制

T1时刻之前就已经发生了错误,复制异常时binglog日志中记录的错误时间点早于T1时刻,slave导入数据之后,日志开始应用的位置是早于T1而不是从T2开始,那么salve节点将会重复故障点到T2时刻的操作,结果大概率是报错,或者是主从数据仍然不一致。

那么可以临时跳过出错的表(REPLICATE_WILD_IGNORE_TABLE),主从复制无延迟的时候再进行修复导出导入的修复操作,还是以上面的图为例:

假定数据是持续变化的,修复过程中salve不停止应用日志,且复制基本无延迟:

  • T1时刻在master导出数据表
  • T2时刻在slave导入数据表,并取消REPLICATE_WILD_IGNORE_TABLE设置,重启slave复制

那么slave节点将缺少T1至T2时刻的数据表的数据变更,结果要么无法启动复制要么数据存在不一致,存在后续复制异常的隐患。

既然导数过程种slave复制正常运行会导致异常,那停止slave复制后再修复是怎样的呢,下面来看一下:

  • T1时刻在slave停止复制
  • T2时刻在master导出数据表
  • T3时刻在slave导入数据表,并取消REPLICATE_WILD_IGNORE_TABLE设置,重启slave复制

那么slave节点将重复T1至T2时刻的数据表的数据变更,结果要么无法启动复制要么数据存在不一致,存在后续复制异常的隐患。

既然无论slave是保持复制还是停止复制,数据都不对,那正确操作是怎样的?


[ 正确操作 ]

既然无论slave是保持复制还是停止复制,数据都不对,那正确操作是怎样的?假如salve节点在a时刻停止复制,master在b时刻导出数据,如a时刻salve节点应用binlog的位置和b时刻Masterbinlog位置相同即可确保数据一致,该操作几乎无法人为确保,但是我们可以确a和b之间数据表没有数据变更,下面描述具体过程:

mysql8主从恢复 mysql主从修复_mysql自动停止运行

  • T1:设置数据表只读

lock tables aa read;

  • T2:停止slave复制(复制无延迟的情况下,确保停止时间点在T1之后)
  • T3:一致性导出数据表
mysqldump -uroot test aa--set-gtid-purged=OFF --single-transaction > aa.sql

导出后可解锁master上的锁定,减少业务影响时间,如执行如上语句做一致性快照导出,导出开始后即可解锁master,无需等待导出结束

  • T4:在slave导入数据表,并取消REPLICATE_WILD_IGNORE_TABLE设置,重启slave复制

因为T1至T3时刻数据表没有数据变更,salve复制停止在T1与T3之间,故master和slave数据是一致的,T4时刻开启复制应用,salve从T2时刻的日志开始应用,数据一致,不会发生异常。

除了以上方式将数据修复一致之外,还可以使用pt-table-sync,以及传输表空间的方式进行数据修复,甚至手工处理差异的数据,视具体场景(差异量,影响范围,修复所需时间及影响)选择合适的修复方式。


[ 预防问题 ]

相比修复问题,日常预防问题发生更加重要,异常宕机以及人为操作常常导致数据差异。

异常宕机:可通过更安全的配置选项规避,但安全性和性能往往不能兼得,需要结合具体业务评估。

人为操作:我遇到的数据不一致大部分为非运维人员不恰当的操作导致数据差异,设置salve节点只读可有效避免。