mysql5.7基于GTID主从切换

本文接上篇《mysql5.7基于GTID搭建主从》。

当前有master,slave,standby,其中slave和standby节点都是slave身份。

现在,我将通过stop slave模拟slave节点同步延迟,然后kill -9模拟master宕机,然后将拥有最新数据的standby提升为master,并令slave同步standby的数据。

真正的failover主从切换,还会多一个步骤,就是如果master机器仍旧可以登录则将master上未同步到slave的binlog重放给slave,本篇博客不研究这个问题。

模拟主从切换

应读者要求,在此首先列出3台服务器的SERVER_ID映射关系:

  • master:a805814a99c211e79c9e525400caafe4
  • standby:a9012235-99d3-11e7-a3f2-525400caafe4
  • slave:6d167b53-99c4-11e7-bada-525400caafe4

首先登录slave,令其停止同步,这相当于模拟了slave节点同步延迟。

然后,我们对master内的数据做一次更新,这样slave相当于延迟没有同步到新的变更,而standby可以立即同步到新的变更:

接着找出master进程ID,将其杀死:

现在相当于master出现了故障。在紧急故障处理时,优先确保master已经死绝,避免半死不死造成脑裂。

然后,我们登录slave和standby执行show slave status,确认它们已经将现有relay-log全部重放完成,以standby为例:

可见提示,Slave has read all relay log,说明standby节点重放完成,它最新GTID是a805814a-99c2-11e7-9c9e-525400caafe4:6。同样的,观察slave节点确保它也重放完成,最新GTID是a805814a-99c2-11e7-9c9e-525400caafe4:5:

接着,我们对比slave和standby这两个从节点谁的数据比较新,拥有较新数据的应该提为master,这样可以尽量减少宕机带来的数据损失,

slave节点的Executed_Gtid_Set为a805814a-99c2-11e7-9c9e-525400caafe4:1-5(我们模拟了同步延迟),而standby是a805814a-99c2-11e7-9c9e-525400caafe4:1-6,说明standby数据比较新,因为我们刻意模拟slave节点同步延迟并在master做了一次更新。

另外也可以通过观察同步master binlog的偏移量来判断谁更新。

slave节点:

standby节点:

可见,standby节点已经读到master的binlog.00005了,显然要领先于slave读取的binlog.00002文件。

接下来,我令standby成为master,也就是关闭它的read_only和super_read_only:

然后,令slave节点停止同步,并定向到standby(端口是3308)作为master:

观察此时slave节点的同步状态:

可见当前slave最新GTID还指在5,落后于standby的1-6。现在我们启动slave对standby的同步,并再次观察:

可见Executed_Gtid_Set已经完成对6的同步,查看数据已经得到更新:

现在,我们向新master节点更新一次数据:

登录slave,确认是否可以正常同步:

a9012235-99d3-11e7-a3f2-525400caafe4:1-2的前半部分就是standby节点的SERVER_ID哈希值,1-2是自增ID,可见最新一次修改应该是正常同步了过来。查看数据表以便确认:

当然,我们最好也确认一下master和slave生成的binlog是否保持了一致:

slave上多的6d167b53-99c4-11e7-bada-525400caafe4:1是我们初始化slave时候set password留下的一个本机GTID,其他均是一样的。

更多问题

假设standby机器性能一般,但是数据较新;slave机器性能好,但数据较旧。那么,我可能选择用slave节点作为新的master,但是它数据比standby少,怎么办?

以当前掌握的知识,我只能先让slave同步standby的数据,然后再将这个关系反转回来,这样基于主从同步技术完成数据补齐最简单,直接操作binlog的方法我暂时还没有学到。另外一个思路是,直接把最新slave的所有数据通过dump工具(xtrabackup )拷贝出来,然后对其他slave逐个停机完整替换数据重启,这样也是一种追平数据的思路,可以参考这里

其实,官方已经提供了failover切换的工具:mysqlfailover,它需要单独安装。这个工具可以帮我们监视mysql集群的健康情况,当master宕机后自动完成整个切换过程,你可以参考这个博客《mysql5.6自动failover》。

添加新的slave

添加新的slave并不复杂,从master dump出最新的数据,拷贝给新的slave,然后再change master to即可。

首先,我去新的master节点(standby)做一次数据的dump,这里我使用mysqldump工具,生产环境应该使用更快的开源工具xtrabackup。

假设现在master机器修理完成,我想让老的master机器成为一个slave节点,所以先要删除master的所有数据,然后重新初始化并启动它。

作为一个slave,必须首先关闭super_read_only(因为my.cnf里配置了On):

然后set password设置你的密码,最后恢复read_only:

上述改密码是写操作,所以会导致产生了binlog,你可以查看一下:

作为一个slave,应该保障binlog和master一致,这样后续failover充当master时才能保证一致性,所以我们这里执行reset master来清理掉当前产生的binlog,另外这也是恢复dump要求的一个必须操作,否则dump文件无法复原:

现在Executed_Gtid_Set已清空,binlog恢复为00001文件,这是一台完全崭新的mysql节点。现在,我们将dump文件导入进来:

再次连接mysql,查看gtid状态:

发现binlog文件并没有增长,但其实已经将来自standby的事务全部执行完成(Executed_Gtid_Set),同时因为binlog文件并没有记录下来,所以gtid_purged=executed_gtid_set,表示这些gtid的binlog都已删除,不在本机存在。

为什么会有这种效果呢?其实看看dump文件里的语句就知道是什么原理了。

在dump头部首先关闭了log_bin,也就是不再输出binlog,并且设置了GTID_PURGED包含了这些即将执行的GTID SET:

接下来执行所有的事务,最后再恢复log_bin配置:

现在要做的,就是change master to,让这个新的slave(原master)和新的master(standby)自动进行GTID交互,完成主从同步。

大功告成!

具体过程可以参考博客:基于mysqldump搭建gtid主从

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~