GTID 详解
前言
gtid 功能是 mysql5.6 版本开始新加入的特性,在 5.7、8.0 及以上版本中做了加强,特别是从 mysql8.0 版本开始,应该是主推基于 gtid 模式的复制了。通过 gtid 保证了每个在主库上提交的事务在集群中有一个唯一的 ID。这种方式强化了数据库的主备一致性,故障恢复以及容错能力。虽说 gtid 是 mysql5.6 加入的特性,但是在 5.6 版本中并不支持该功能,也就是说 mysql5.6 版本中无法开启该功能。5.7 版本中 即使没有开启 gtid,默认也会以匿名的方式记录 gtid,匿名的方式记录的 gtid 是由系统进行管理和维护的,我们是无法使用的。所以 如果要搭建 mysql 主从复制模式,并且是基于 gtid 模式进行复制的话,mysql 版本最低是 5.7 的版本。
在传统的 mysql 基于二进制日志的模式复制中,从库需要告知主库 要从哪个二进制日志文件中的那个偏移量进行增量同步,如果指定错误会造成数据的遗漏,从而造成数据的不一致。借助 gtid,在发生主备切换的情况下,mysql 的其它从库可以自动在新主库上找到正确的复制位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。另外,基于 gtid 的复制可以忽略已经执行过的事务,减少了数据发生不一致的风险。所以说,相比 mysql 传统的主从复制模式,gtid 模式的复制对于 DBA/开发人员/运维 等相关技术人员更加友好。实际上 gtid 这个功能 主要是为了主从复制而来的,gtid 是为了代替 mysql 传统的主从复制模式(通过某一个 binlog 二进制日志文件中的 pos 位置偏移量等相关信息 来进行复制)。当然了,gtid 在单机状态下 作用不是很大,它主要还是为了主从而来的。
可能大多数人第一次听到 gtid 的时候会感觉有些突兀,但是从架构设计的角度,gtid 是一种很好的分布式 ID 实践方式,通常来说,分布式 ID 有两个基本要求:
①、全局唯一性
②、趋势递增
这个 ID 因为是全局唯一,所以在分布式环境中很容易识别,因为趋势递增,所以 ID 是具有相应的趋势规律,在必要的时候方便进行顺序提取。所以换一个角度来理解 gtid,其实是一种优雅的分布式设计。
GTID 的基本概念和组成(Global Transaction ID)
GTID (Global Transaction ID) 是对于一个已提交事务的编号,并且是一个全局唯一的编号。 GTID 实际上是由 server_uuid+transaction_id 组成的。
server_uuid:是一个 mysql 实例的唯一标识,每一台 mysql 实例的 server_uuid 都是不同的,在 mysql 第一次启动时,会自动生成并持久化到 auto.cnf 文件(存放在 mysql 的数据目录下,这是一个非常重要的文件,不能删除,这一部分是不会变的),也可以在 mysql 中执行 select @@server_uuid;命令查看当前 mysql 实例的 server_uuid,显示的结果就是 auto.cnf 文件中保存的 server_uuid。
transaction_id:代表了该实例上已经提交的事务数量,transaction_id 是一个从 1 开始的自增计数,表示在这台 mysql 实例上执行的第 n 个事务。并且随着事务的增加,值一次递增(也就是 值依次+1)
注意:这里的事务和 innodb 中的事务是不一样的,innodb 中的事务 指的是 DML 语句的操作,而 gtid 中的事务(transaction_id)指的是 binlog 中的事件,如果不理解 binlog 中的事件,可以理解为 gtid 中的事务,包含了 DDL、DML、DCL 等语句。
小总结:gtid 就是 事务的 ID,唯一识别号,全局唯一。随着事务记录到 binlog 中,用来标识事务。每一个事务都有一个 gtid_log_event(gtid 的日志事件)。
下面是一些 gtid 的具体展现形式:
0a27af20-28d1-11ea-8a83-fa163e680ae8:1 // 表示 在以 0a27af20-28d1-11ea-8a83-fa163e680ae8 为 唯一标识的 mysql 实例上执行的第 1 个数据库事务。
一组连续的事务可以用 - 连接的事务序号范围表示。例如:0a27af20-28d1-11ea-8a83-fa163e680ae8:1-5
gtid 可以包含来自多个 mysql 实例的事务,它们之间用“,”(英文逗号)分隔。如果来自同一 mysql 实例的事务序号有多个范围区间,各组范围之间用冒号分隔。例如:
0a27af20-28d1-11ea-8a83-fa163e680ae8:1-5:11-18,
0a27af20-28d1-11ea-8a83-fa163e680ae8:1-27
GTID 的开启
主要是通过 2 个配置选项参数来控制 gtid 功能的开启,在 mysql 配置文件中的 mysqld 标签下增加以下 2 个配置,然后重启 mysql 即可开启 gtid 功能
查看 gtid 是否开启
ON 表示开启,OFF 表示未开启
开启 gtid 后,查看当前二进制日志文件的状态:
Executed_Gtid_Set 这一列非常关键,它表示:执行过的 gtid 的集合,开启 gtid 之后,这一列就会显示一共产生了多少 gtid 的信息了。
创建一个测试数据库,再次查看 Executed_Gtid_Set 这一列的值,就会发现这一列已经产生了 gtid 的信息了:
通过上图可以看到已经产生了 gtid 的信息了。
此时看一下,开启 gtid 之后,mysql 在 binlog 日志文件中的事件这里是如何记录的:
mysql> show binlog events in '你的 binlog 日志文件名称';
示例截图如下:
上图中可以看到 binlog 中的一些具体信息,包括事件类型(Event_type)有的是 gtid 类型。有了 gtid 之后,就可以不用管 pos 和 end_log_pos 这 2 个列的值了,直接通过 gtid 就可以管理 binlog 日志,可以通过 gtid 截取日志、数据恢复等操作。
上图中 Info 这一列可以看到 SET @@SESSION.GTID_NEXT= '0a27af20-28d1-11ea-8a83-fa163e680ae8:1' 这一行信息, 其中 0a27af20-28d1-11ea-8a83-fa163e680ae8 就是前面提到过的 server_uuid,而 1 就是 transaction_id(事务 id)。
注意:上面使用的是 DDL 语句,在 binlog 日志文件中,gtid 是这样记录的。
使用 DML 语句,然后观察下 在 binlog 中,DML 语句的操作,gtid 是如何记录的?
DML 语句,在 gtid 中的记录 是 如下图中的记录形式的:
如上图所示,DML 的语句,gtid 是以 begin 开始、commit 结束 作为一个 gtid 的记录。
**小总结:**每一个 DDL 语句都是一个 gtid 记录,而 DML 语句 是以 begin 开始、commit 结束 为一个 gtid 记录。这个就是 gtid 的记录方式,要搞清楚。
基于 GTID 进行日志截取
基于 gtid 进行日志截取也是使用 mysqlbinlog 工具进行截取,一般都是配合以下三个参数进行配合使用。
①、--include-gtids // 截取指定的 gtid
②、--exclude-gtids // 排除指定的 gtid
③、--skip-gtids // 跳过 gtid 的幂等性机制的检查,也可以理解为,截取日志的时候 不带有 gtid 的信息
截取示例:
GTID 的幂等性
幂等性:用户对同一操作,发起一次或多次请求的数据结果是一致的,不会因为多次请求而导致最终的数据结果不一致的问题。(前提是:在具备幂等性机制的这种情况下)。简单来说 就是 不重复操作。
mysql 开启 gtid 之后,binlog 就具备了幂等性的机制了。
如果在基于 gtid 进行数据恢复的时候,你在截取 gtid 记录时,没有加--skip-gtids 这个选项的话,那你在 mysql 使用 source 命令导入 sql 文件 进行数据恢复的话,会发现 数据并没有恢复成功。就是因为 gtid 集合中已经有了这些 gtid 记录,而基于幂等性的机制,已经有的 gtid 是不会进行操作的,既然不会进行操作,那自然数据恢复就不会成功了。
可以观察下,gtid 日志截取的时候,截取 2 个 然后分别保存这 2 个文件,其中一个截取的时候加--skip-gtids 选项另一个截取的时候不加--skip-gtids 选项,然后分别打开这 2 个文件,仔细观察 2 个文件中的内容就会发现,加了--skip-gtids 选项的文件里面 没有 gtid 的信息(文件里面没有 SET @@SESSION.GTID_NEXT='xxxxxx' 没有这行 gtid 记录的信息),所以在数据恢复的时候,会跳过 gtid 的幂等性机制检查,从而数据恢复成功。
**小总结:**开启 gtid 后,mysql 在恢复 binlog 时,重复的 gtid 的事务(gtid 记录)就不会在执行了。所以说,如果是基于 gtid 进行数据恢复的时候,一定要注意 gtid 的幂等性这个机制。因为 一不小心就恢复失败。
基于 GTID 的数据恢复
配合上面的 gtid 日志截取,完事后,在 mysql 里面使用 source 命令进行导入 sql 文件即可。不要忘了 截取 gtid 日志记录的时候,加上--skip-gtids 这个选项。好吧,举个栗子吧:
然后,在 mysql 中使用 source 命令进行数据恢复:
**小总结:**基于 gtid 数据恢复的时候,一定要仔细查看到底要截取那些 gtid 记录进行数据恢复,避免截取 gtid 记录的时候 把那些 drop、delete 等操作的 gtid 也给截取出来了,导致数据恢复的时候,又相当于删除了。。
版权声明: 本文为 InfoQ 作者【乌龟哥哥】的原创文章。
原文链接:【http://xie.infoq.cn/article/44794a2bd5f0b3f7048beda8a】。文章转载请联系作者。
评论