关于MySQL GTID的一次深刻学习

2019-12-24 13:32:44 浏览数 (2)

最近因为一个特别的操作需求,需要临时配置一下双主复制模式。

在这个过程中让我从开始的悲观,无助到理解后的喜悦,GTID的使用模式确实给了我很多的意外惊喜,也让我对这个特性的过程有了进一步的理解。

我在书中对于GTID的特性使用了如下的图来表达。

现在的场景是一个一主一从的数据库,已经配置了从库。

在上线前进行了模拟演练,做过主从切换,然后快速验证后又恢复了回来。现在想要实现的是一个双主的配置,即需要Slave->Master做一个反向的复制配置。

我在检查的时候,发现主从都存在两个GTID属主。

类似这样:

代码语言:javascript复制
Executed_Gtid_Set: 
74a1e34b-8204-11e9-b7dd-005056b73821:1-20352047366,
99fbf089-9266-11e9-9a38-005056b70e42:1-5046391

其实这是因为在数据库运行过程中确实发生了两次切换导致,也通过这种方式能够清晰的记录下来GTID的变更历史,这本来没什么好说的,在配置反向关系的时候抛出了错误。

代码语言:javascript复制
Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'

从错误信息来看,Master切换之后,Slave变成了主库,这个时候数据写入就在Slave端了,然后业务再次切换后数据开始在Master写入。这个过程中的切换会导致一部分的binlog写入是在Slave端生成,而这部分的binlog显然随着时间的变化会自动被服务清理掉。如果报出这样的错误,实在是比较尴尬和无奈的事情了,换句话说,我们要关注当前的状态和后续的改变,binlog我们不可能自始至终保留,而且就算保留拿来恢复也不显示,所以在这个过程中一定有什么特别的地方。

我把主从关于GTID的信息都整理出来,可以参考梳理后的结果。

在Master和Slave的UUID分别是以21和42结尾,仔细对比发现了端倪。

Master端:

Gtid_purged:

74a1e34b-8204-11e9-b7dd-005056b73821:1-20294065566,

99fbf089-9266-11e9-9a38-005056b70e42:1-5046391

Slave端

Executed_Gtid_Set:

74a1e34b-8204-11e9-b7dd-005056b73821:1-20354149730,

99fbf089-9266-11e9-9a38-005056b70e42:1-5046473

gtid_purged:

74a1e34b-8204-11e9-b7dd-005056b73821:1-20295253841,

99fbf089-9266-11e9-9a38-005056b70e42:1-5046473

42结尾的Slave端是做过一次故障切换的,切换后的状态应该是

1-5046391左右,而在Slave变为主库后写入了数据,状态应该是

1-5046473,总之在那之后基于这个GTID再无数据写入,具体在那个时间段里发生了什么已经无法知晓,但是一个值得考虑的点就是基于MHA的健康监测是使用了ping insert的方式,在没有业务数据干扰的情况下,很可能是这个潜在的原因写入了数据,但是至于为什么没有把这些变更都同步过去,这是一个问题。当然对我们解决这个问题不是最重要的。

我们可能需要理解一下这个问题的根本原因,其实不在于是不是存在两个GTID,而是根本在于Slave端的GTID(不变化的GTID)在两端不一致。

可以举个例子,比如夫妻两个人(类似于Master,Slave两个节点,为了便于理解,我就以媳妇(Master),丈夫(Slave)来简称了),先是媳妇管账,GTID以媳妇(Master)的变化为准,然后过了一段时间发生了转换,该丈夫管账,数据变化以Slave为主,结果管得不好,很快又换过来了,于是又以媳妇的(Master)为准。

隔了很久,夫妻两人要共同管账(配置双主模式),需要把之前的消费情况理一理。 结果发现丈夫(Slave)管账的时候有一部分的账目不一样,即媳妇(Master端)看到的账目和丈夫(Slave端)看到的不一样,媳妇这边是5046391笔交易,丈夫这边记录的是5046473笔交易,结果丈夫也记不得这个过程的消费记录,所以这种情况下就需要做一些修正和稽核。

这个情况有些类似,我们的思路是先修正两边的GTID(不变化的部分),然后再重新建立双向复制关系。

修复过程

修复过程其实比较清晰,那就是现在是以Master端的GTID为准,那么我们就不能在Master端做任何reset master的操作,所以记录的修正应该是以Master为准,所有的操作应该是在Slave端完成。

Slave端修复的步骤如下:

1)stop slave;

2)show slave statusG

记录下来得到的Executed_Gtid_Set值,这是截止stop slave时最新的GTID状态信息。

3)reset master;

切记是在Slave端执行,这个阶段的目的就是要重新配置GTID的校准值。这个时候mysql.gtid_executed应该就是空的了。

4)重置GTID_purged值

这个步骤是关键所在。我们需要配置为最新的SET的GTID值,这样就不用重复消费哪些事务数据了,而原来的GTID从5046473修改为5046391

SET @@GLOBAL.GTID_PURGED='74a1e34b-8204-11e9-b7dd-005056b73821:1-20363492180,99fbf089-9266-11e9-9a38-005056b70e42:1-5046391';

5)删除从库的复制配置

reset slave all;

6)配置复制关系

CHANGE MASTER TO MASTER_USER='dba_repl', MASTER_PASSWORD='xxxx' , MASTER_HOST='xxxxx',MASTER_PORT=4307,MASTER_AUTO_POSITION = 1;

7)重启Slave节点,查看状态

start slave;

show slave statusG

修复完成后,再次建立复制关系就是水到渠成的事情了,当然也可以随建随删。

0 人点赞