3.5 GTID运维
每个GTID唯一标识构成事务的一组二进制日志事件,在二进制日志中跟踪GTID事务与其事件集之间的映射。应用连接到数据库时,MySQL服务器自动跳过之前已处理的GTID事务,此行为对于自动复制定位和正确的故障转移至关重要。启用GTID也给运维带来了一些改变。
3.5.1 跳过一个事务
传统基于GTID二进制位置的复制中,从库由于某些错误导致复制中断时,一个可能的解决方案是设置sql_slave_skip_counter全局系统变量,跳过导致错误的事件,然后重启复制。但是,在启用GTID后,执行的单位由事件变为事务,因此该方法不再有效(slave_skip_errors仍然可用),并会报出以下错误:
从错误信息可以看到,GTID跳过事务的方法是注入一个空事务,具体步骤如下:
步骤01 定位出错事务的GTID。我们需要获得从库执行的最后一个事务,方法有:show slave status \G中的Executed_Gtid_Set,show global variables like '%gtid%';中的gtid_executed,show master status;中的Executed_Gtid_Set。
步骤02 将会话级系统变量gtid_next设置为上一步的GTID,如:set gtid_next='8eed0f5b-6f9b-11e9-94a9-005056a57a4e:980058'。注意gtid_next的值只能是单个GTID。
步骤03 注入空事务:begin;commit;。
步骤04 重启复制:set gtid_next='automatic'; start slave;重启复制前需要将gtid_next设置为默认值'automatic'。下面是跳过多个事务的一个例子:
stop slave; set gtid_next='8eed0f5b-6f9b-11e9-94a9-005056a57a4e:980055'; begin;commit; set gtid_next='8eed0f5b-6f9b-11e9-94a9-005056a57a4e:980056'; begin;commit; set gtid_next='8eed0f5b-6f9b-11e9-94a9-005056a57a4e:980057'; begin;commit; set gtid_next='automatic'; start slave;
3.5.2 mysqldump导出
使用mysqldump受set-gtid-purged选项影响,set-gtid-purged选项设置为AUTO(默认值)或ON时的输出如下所示:
开始部分的SET @@SESSION.SQL_LOG_BIN=0用于防止导入数据时基于本地服务器生成新的GTID。接着GTID_PURGED被设置为备份时刻已经执行过的GTID事务,该操作将会初始化mysql.gtid_executed表、gtid_purge变量及gtid_executed变量。当mysqldump命令加入--set-gtid-purged=off选项时,则输出中不会加入SQL_LOG_BIN=0和GTID_PURGED的设置。如果要将数据导入从库进行初始化,则不能设置--set-gtid-purged=off。下面是这个选项的含义:
细心的读者到这里可能心生疑问:为初始化从库数据,命令行使用了--all-databases选项。mysql.gtid_executed表会不会被重建,进而通过GTID_PURGED设置的mysql.gtid_executed表会重新改变,重启数据库后读取mysql.gtid_executed表可能获得错误GTID集合导致复制错误?答案也在mysqldump的输出中。
首先,如果从库实例的mysql库存在,则不会删除重建:
其次,如果mysql.gtid_executed表存在,则不会删除重建。最后,如果该表不存在,则创建它,但不会向其加载数据。由此得出结论,除非手工删除了mysql.gtid_executed表,否则不会因它造成复制问题,至少MySQL 8是这样。具体如下所示:
3.5.3 主从切换
这里分三种情况进行讨论:从库只读、从库读写并且有全部写操作的二进制日志、从库读写但写操作的二进制日志不全。
1. 从库只读
这种情况从库(新主库)没有执行过本地的事务,只需执行正常切换:
新主库会生成自己的GTID事务,此时会出现两个server_uuid对应的GTID:
2. 从库读写并且有全部写操作的二进制日志
此时从show slave status的输出中可以看到:
刚才从库执行的三个本地事务,在新从库上正常复制。因为本地事务与复制事务GTID的server_uuid部分不同,只要binlog保留完整,从库上的写操作在主从切换后可以自动复制到新的从库上,与匿名复制相比明显方便许多。
3. 从库读写但写操作的二进制日志不全
此时在show slave status的输出中报错如下:
真实环境中要是遇到这种情况建议还是重建从库。二进制日志文件默认的保留时间是30天(binlog_expire_logs_seconds=2592000)。一般来说从库的写操作通常是为保留一些报表结果或临时数据,这些操作的最早时间很大可能已超过三十天,在这之后进行主从切换就会出现问题。这也是建议从库readonly(只读)的原因之一。如果确实要执行比如加索引等不影响数据的操作,则可以在执行前将sql_log_bin变量设置为0,这样不会增加本地GTID:
set sql_log_bin=0; create index idx1 on test.t1(a);
但还是要强调,从库最好始终readonly。