最近一位同学遇到的案例:凌晨数据库意外宕机,要求在一主两从的基础上,搭建MHA做故障切换。在部署测试中遇到一些问题找到我,交流的过程挖出一些之前忽略的坑,感谢这位同学无私分享!
• GTID环境,KILL主库,新主库和从库丢失数据(之前已知)
• 在数据库进程挂掉、数据库服务器关机或重启、开启防火墙、关闭网络服务等状况下,测试MHA是否正常切换(之前没考虑脑裂问题)
• 线上部分环境GTID,Auto_Position=0,故障切换会变成GTID,Auto_Position=1(之前没考虑)
• 梳理故障切换流程(之前梳理)

一、GTID环境,KILL主库,新主库和从库丢失数据

需在配置文件将Master/Binlog Server配置到[binlogN],才能补全Dead Master上的差异数据,否则只应用到Latest Slave
发散:[binlogN]指定到Binlog Server,kill -9 master_mysqld,MHA是从Binlog Server上获取还是从Dead Master上获取差异binlog?
指定到Binlog Server就从Binlog Server上获取,指定到Dead Master就到Dead Master获取;如果没有指定,就不会补全差异数据

二、MHA切换测试

在数据库进程挂掉,数据库服务器关机或重启、开启防火墙、关闭网络服务等状况下,测试MHA是否正常切换
MySQL5.7.21,基于Row+Gtid搭建的一主两从复制结构:Master132->{Slave133、Slave134};VIP在132上,mha-manager 0.56在134上

测试场景XX.132XX.133XX.134说明
132:kill -9 mysqld不可用MHA正常切换,数据不丢失
132:关闭或重启132服务器不可用MHA正常切换,数据可能丢失
134:iptables -I INPUT -s XX.132 -j DROP可用MHA正常切换,原主库正常访问,133成为新主库,132和133同时存在VIP
132:service network stop/ifconfig eth0 down不可用MHA正常切换,数据可能丢失

注:上述表格是配置[binlogN]指定到Binlog Server,没有指定secondary_check_script的测试结果
关闭数据库服务器,数据可能丢失的原因:Binlog Server是异步,高并发下binlog延迟可以理解
开启防火墙,模拟主库与mha-manager不通讯,出现脑裂。配置文件添加"secondary_check_script=masterha_secondary_check -s remote_host1 -s remote_host2",remote_host1、remote_host2尽量与mha-manager、MySQL Server处于不同网段

三、GTID,Auto_Position=0,故障切换变成GTID,Auto_Position=1

3.1、Auto_Position

线上部分环境GTID,Auto_Position=0,故障切换会变成GTID,Auto_Position=1
• 有何风险
如果S1从库的GTIDs存在空洞,S2从库的GTIDs正常,随着时间推移,S2将S1上GTIDs空洞对应的binlog删除。此时发生故障切换,且选择S2做为新Master,在S1 change master to S2 master_auto_position=1会报错

Got fatal error  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.'

从库存在GTIDs空洞可能会导致切换异常:VIP正常切换,新主可用,新从到新主之间的复制报错,只有修复主从报错,才会做后续操作(new master cleanup、Failover Report、send mail)
• 为何不直接修改为GTID,Auto_Position=1
Slave GTIDs<Master GTIDs,如果Diff GTIDs对应的binlog在Master已被purge,修改为Auto_Position=1会继续报错
Slave GTIDs>Master GTIDs,5.7下主从直接报错
• 如何解决
修改源码~~~

shell> vim /usr/share/perl5/vendor_perl/MHA/ServerManager.pm
return if ( $_->{use_gtid_auto_pos} );
-->修改为
#return if ( $_->{use_gtid_auto_pos} ); shell> vim /usr/share/perl5/vendor_perl/MHA/MasterMonitor.pm
if ( !$_server_manager->is_gtid_auto_pos_enabled() ) {
$log->info("GTID (with auto-pos) is not supported");
-->修改为
if ( $_server_manager->is_gtid_auto_pos_enabled() != ) {
$log->info("GTID (with auto-pos) is not supported");

为啥这样修改表示看不懂,感谢顺子(另一位同学)分享~
注意:传统复制(gtid_mode=off),MHA不会利用Binlog Server补全差异数据(又是一个坑●-●)

3.2、什么情况会出现GTID空洞

1、从库暂停Slave Thread->主库写数据->主库flush log、purge log->从库启动Slave Thread->报错,缺失binary log
手工执行change master_auto_position=0;change binlog file & pos;
2、搭建复制时change master_auto_position=0;->复制过程暂停Slave Thread->change new_file & new_pos->从库启动Slave Thread
master_auto_position=1,Slave连接Master时,会把Executed_Gtid_Set中的GTIDs发给Master,Master会跳过Executed_Gtid_Set,把没有执行过的GTIDs发送给Slave
情况1:再次change master_auto_position=1;它依旧会去查找那些被purge的binlog,然后抛出错误
情况2:再次change master_auto_position=1;只要主上对应binlog没被purge,它能自动将空洞GTID补全
前提:Master没有对GTIDs空洞相应的记录进行DML操作,不然复制早就报错了,可能就错过这个坑~不过仔细想想,从库本来就有空洞,复制也没报错,侧面反映Master没有对GTIDs空洞相应的记录进行DML操作
扩展阅读:[MySQL FAQ]系列 — 5.6版本GTID复制异常处理一例

3.3、relay-log是如何获取及应用

Slave GTIDs>Master GTIDs,relay-log是如何获取及应用

• GTID,auto_position=
Master
Executed_Gtid_Set:90b30799--11e7--000c29c1025c:-
Slave
set global Gtid_Purged='90b30799-9215-11e7-8645-000c29c1025c:1-6:8-24';
-->Master写入一条数据
Master
Executed_Gtid_Set:90b30799--11e7--000c29c1025c:-
Slave
Retrieved_Gtid_Set: 90b30799--11e7--000c29c1025c:
Executed_Gtid_Set: 90b30799--11e7--000c29c1025c:-:-

新写入的binlog会写到从库的relay-log,但是不会应用(可以通过查看数据、解析日志确认)!

• GTID,auto_position=
change master to master_auto_position=;
启动复制报错
Last_IO_Error: Got fatal error from master when reading data from binary log: Slave has more GTIDs than the master has, using the master`s SERVER_UUID. This may indicate that the end of the binary log was truncated or that the last binary log file was lost, e.g., after a power or disk failure when sync_binlog != . The master may or may not have rolled back transactions that were already replica

relay-log获取
Auto_Position=0,如果开启relay-log自动修复机制,发生crash时根据relay_log_info中记录的已执行的binlog位置从master上重新获取写入relay-log
Auto_Position=1,Slave连接Master时,会把Executed_Gtid_Set中的GTIDs发给Master,Master会跳过Executed_Gtid_Set,把没有执行过的GTIDs发送给Slave。如果Slave上的GTIDs大于Master上的GTIDs,5.7下直接报错,5.6下不会报错(有环境的自行验证,顺便看看relay-log会不会有记录写入)
relay-log应用
如果relay-log中的GTIDs包含在Executed_Gtid_Set里,则不会apply-log

四、故障切换流程

MHA在传统复制和GTID复制下,主库发生故障,如何选举New Master,如何修复差异数据
详细流程请参考:MHA-手动Failover流程(传统复制&GTID复制)

05-11 22:20