深入理解MySQL 5.7 GTID系列(十):实际案例二

导 读

作者:高鹏(重庆八怪) 原文地址: https://www.jianshu.com/p/2c25842d58d3 深入理解MySQL 5.7 GTID系列文章共十篇,本文为第四篇,点击查看: 第一篇:深入理解MySQL 5.7 GTID系列(一) 第二篇:深入理解MySQL 5.7 GTID系列(二):GTID相关内部数据结构 第三篇:深入理解MySQL 5.7 GTID系列(三):GTID的生成时机 第四篇: 深入理解MySQL 5.7 GTID系列(四):mysql.gtid_executed&PREVIOUS GTID EVENT 第五篇:深入理解MySQL 5.7 GTID系列(五) gtid_executed&gtid_purged什么时候更新 第六篇:深入理解MySQL 5.7 GTID系列(六):MySQL启动初始化GTID模块 第七篇:深入理解MySQL 5.7 GTID系列(七)binlog_gtid_simple_recovery参数的影响总结 第八篇:深入理解MySQL 5.7 GTID系列(八):GTID带来的运维改变 第九篇:深入理解MySQL 5.7 GTID系列(九):实际案例一 本系列文章共十篇,本文为最后一篇。

本案例是我真实遇到过的一个坑,也在前文中不止一次地提到,当时也是非常纳闷,其实知道原因后只能说为什么会这么坑。

一、触发条件

本案列我测试过4个版本: percona Mysql 5.7.14 官方社区 Mysql 5.7.17 percona Mysql 5.7.19 percona Mysql 5.7.15 其中percona Mysql 5.7.14和官方社区 Mysql 5.7.17有这个问题。其他版本未知

  • 已知percona Mysql 5.7.14或者官方社区 Mysql 5.7.17
  • mysqldump备份没有使用 -F, --flush-logs选项
  • Gtid打开

二、故障描述

本故障主要是新搭建的Gtid主从库,运行一段时间后重启主从必然报错如下:

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.'

三、故障分析

为什么重启后会报错找不到事务呢,后来发现这个Gtid事务在主库的binlog中已经没有了,应该是很久以前的。其实这个问题我们要回到mysqldump出来的文件如何进行Gtid的初始化以及mysql.gtid_executed表中。 在mysqldump不使用--set-gtid-purged的时候必然会在dump出来的脚本中包含

-- GTID state at the beginning of the backup 
 SET @@GLOBAL.GTID_PURGED='e859a28b-b66d-11e7-8371-000c291f347d:1-41';

这样一个设置GTID_PURGED的语句,它包含了主库上已经执行的全部Gtid事务。从第五节的源码和总结部分我们知道这个语句至少做了三个更改(DBA可见的只有三个):

  • mysql.gtid_executed表的写入
  • gtid_executed变量的修改
  • gtid_purged变量的修改

而完成了这一步实际上mysql.gtid_executed表是包含了全部的执行过的Gtid事务的,但是随后我们看到dump脚本包含了如下语句

显然这里我们在source的时候从库的mysql.gtid_executed将被重新初始化为:

'e859a28b-b66d-11e7-8371-000c291f347d',1,32

而实际的已经执行过的Gtid是:

'e859a28b-b66d-11e7-8371-000c291f347d:1-41';

如前文第五节我们通过源码分析后总结如下:

mysql.gtid_executed表修改时机
在binlog发生切换(rotate)的时候保存直到上一个binlog文件执行过的全部Gtid,它不是实时更新的。

因此此时表中并没有完全包含全部执行过的Gtid事务,而在前文第六节的源码分析中我们知道在Gtid模块启动的时候必须要读取两个Gtid持久化的介质:

  • mysql.gtid_executed
  • binlog

来判断Gtid的集合,显然从库不可能在binlog包含这个Gtid事务,所以这样的操作步骤就导致了数据库从库后的报错,而这里的正确的步骤是压根不进行mysql.gtid_executed的重建和导入,我发现在percona Mysql 5.7.15和percona Mysql 5.7.19正是这样的。但是为了防范这个问题,我在搭建的Gtid从库导完数据后加入了两个个步骤如下:

reset master;set global gtid_purged='e859a28b-b66d-11e7-8371-000c291f347d:1-41';

这两步也就是为了从新初始化mysql.gtid_executed表,让其正确。 此问题还可以在mysqldump的时候加入-F, --flush-logs选项规避,但是-F会加入如下的MDL LOCK:

这把锁是GLOBAL级别的MDL_SHARED(S)锁,它会等到你说有的SELECT/DML/DDL语句结束后才能获得,同时会堵塞全部的SELECT/DML/DDL虽然持有时间很短如下:

当然要了解MDL LOCK的朋友可以参考我的文章: http://blog.itpub.net/7728585/viewspace-2143093/ MYSQL METADATA LOCK(MDL LOCK)学习(1) :理论知识和加锁类型测试

四、故障模拟

知道了原因后也是很好模拟我使用的版本是社区版5.7.17,搭建过程就是前面说的步骤。只是导完数据后不使用reset master和set gtid_purged表进行重新初始化mysql.gtid_executed表。搭建完成后做几个事务状态正常如下:

mysql> show slave status \G
*************************** 1. row ***************************
              Master_Log_File: binlog.000002
          Read_Master_Log_Pos: 5077
               Relay_Log_File: test1-relay-bin.000002
                Relay_Log_Pos: 2498
        Relay_Master_Log_File: binlog.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 5077
              Relay_Log_Space: 2705
                Last_IO_Errno: 0
                Last_IO_Error: 
        Seconds_Behind_Master: 0
           Retrieved_Gtid_Set: e859a28b-b66d-11e7-8371-000c291f347d:42-49
            Executed_Gtid_Set: e859a28b-b66d-11e7-8371-000c291f347d:1-49
                Auto_Position: 1

但是这个时候我们发现mysql.gtid_executed表已经出现了问题如下:

很容易发现33-41之间是没有持久化的。如果这个时候如果我们使用purge binary logs to 来清理掉主库的日志那么必将出现问题,如果不清理也会出现Gtid事物重新执行的情况。我们做清理模拟线上错误。主库执行:

mysql> show binary logs;
+---------------+-----------+
| Log_name      | File_size |
+---------------+-----------+
| binlog.000001 |      9974 |
| binlog.000002 |      5121 |
| binlog.000003 |       194 |
+---------------+-----------+
3 rows in set (0.01 sec)

mysql> purge binary logs to 'binlog.000003';
Query OK, 0 rows affected (0.04 sec)

mysql> show binary logs;
+---------------+-----------+
| Log_name      | File_size |
+---------------+-----------+
| binlog.000003 |       194 |
+---------------+-----------+
1 row in set (0.00 sec)

备库重启后错误重现:

我们发现I/O thread 试图获取主库的33-41的Gtid事务的事务,已经不能获取,实际上即使能获取也会造成事务的重新执行,我们看到Executed_Gtid_Set已经出现了两个连续的区间:

Executed_Gtid_Set: e859a28b-b66d-11e7-8371-000c291f347d:1-32:42-49

五、总结

前文已经描述过mysql.gtid_executed表的作用和其更改时机,如果我们对其有深刻的了解这个案例也是很容易分析的,当然解决办法在第八节主从搭建的步骤中我已经给出了,也就是在搭建完成后进行reset master和set global gtid_pruged两步重新初始化一下mysql.gtid_executed表。

原文发布于微信公众号 - 3306pai(pai3306)

原文发表时间:2018-04-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏乐沙弥的世界

Percona XtraDB Cluster 5.7 event是否重复执行?

最近的某个业务系统即将由单点转入PXC集群,碰到的问题是mysql单实例上运行的那些event,再转入集群之后,该如何执行呢?带着这个问题,做了个实验,并给出相...

8710
来自专栏乐沙弥的世界

参数CONTROL_FILE_RECORD_KEEP_TIME和MAXLOGHISOTRY

--**************************************************

18230
来自专栏乐沙弥的世界

rman 还原归档日志(restore archivelog)

     听说过还原(restore)数据库,表空间及数据库文件,使用归档日志恢复(recover)数据库,表空间,数据库文件。咦,还有还原归档日志这一说法呢?...

18940
来自专栏YG小书屋

mysql主从配置与数据移植

22150
来自专栏搜云库

CentOs7.3 搭建 MySQL 5.7.19 主从复制,以及复制实现细节分析

CentOs7.3 搭建 MySQL 5.7.19 主从复制,以及复制实现细节分析 概念 主从复制可以使MySQL数据库主服务器的主数据库,复制到一个或多个My...

30250
来自专栏猿人谷

Oracle RAC基本维护指令

所有实例和服务的状态 $ srvctl status database -d orcl Instance orcl1 is running on node l...

22770
来自专栏Jed的技术阶梯

HBase和Hive整合

1-3步骤不是必须的,如果没有进行1-3步骤的设置,那么想要让hive和hbase整合,每次进入hive命令行后,需要进行如下配置:

17630
来自专栏乐沙弥的世界

Oracle健康监控及健康检查(Health Monitor)

Oracle数据库包括一个名为Health Monitor的框架,用于运行诊断检查数据库的各种组件。Oracle健康监视器检查各种组件数据库,包括文件,内存,事...

26600
来自专栏Angular&服务

关于ng build编译报错

1.在项目 myProject\node_modules\.bin 文件夹下面找到ng.cmd 和 ngc.cmd 文件添加配置信息

8220
来自专栏数据和云

你不可不看的 Oracle RAC 日常基本维护命令

$ srvctl status instance -d orcl -i orcl2

12640

扫码关注云+社区

领取腾讯云代金券