文章目录
GTID 背景
GTID(global transaction identifier,全局事务 ID)是 MySQL 5.6 版本引入的新特性,它会为每个事务分配一个唯一事务 ID。事务 ID 的格式如下。
source_id:transaction_id
其中,source_id 表示事务在哪个实例上产生的,对应的是该实例的 server_uuid。transaction_id 是事务的序列号,按照事务的提交顺序从 1 开始顺序分配。
在传统的复制关系中,是基于 Binlog 位点,在搭建的时候需要指定 Binlog 文件和 position 位点。这个位点非常关键,如果有误差或者弄错了,很容易导致主从不一致,甚至会中断主从复制。
在一主多从的架构中,当主库发生故障,将一个备库提升为主库后,剩下的从库不知道要基于哪个位置点与新的主库建立复制关系。毕竟,主库上的同一个操作,在不同从库上对应的 binlog 位置点基本都不相同。这也是 MHA 这类复制管理工具的出现背景,它能自动计算出搭建复制需要的位置点,但在更复杂的复制拓扑(如级联复制)中,位点信息很难保障计算准确,类似复制管理工具也无能无力。此时 GTID 诞生了,集群中每个事务都有独立的全局唯一 ID,简化了复制的日常管理。
生产环境上也会遇到需要开启 GTID ,有什么风险?如何在线开启?本篇文章将着重介绍。
GTID 限制
由于基于 GTID 复制依赖于事务,所有开启 GTID 时,有些 MySQL 特性不支持:
- 事务中混合多个存储引擎。
- 主从库表引擎不一致,会导致数据不一致。
- 不支持 CREATE. TABL…SELECT。
- 不支持 CREATE TEMPORARY TABLE 和 DROP EMPORARY TABLE。
PS:详细可参考 Restrictions on Replication with GTIDs
参数介绍
开启 GTID 我们一般会关注 gtid_mode
和 enforce_gtid_consistency
两个参数。
enforce_gtid_consistency
当 GTID 开启后,一个事务分配一个 GTID 保护 GTID 一致性,对某些 SQL 会有限制,例如 CREATE TABLE … SELECT 必须得分成两条语句执行。该参数有三个有效值:OFF / ON / WARN
。
- OFF:表示事务允许违反 GTID 一致性。
- ON:表示事务不允许违反 GTID 一致性,有相关 SQL 会直接返回异常。
- WARN:表示事务允许违反 GTID 一致性,但会将警告信息记录到 ERROR LOG。
gtid_mode
GTID 模式设置,该参数有四个有效值:
- OFF:表示生成的是匿名事务,从库只能应用匿名事务。
- OFF_PERMISSIVE:新产生的事务都是匿名事务,但也允许有 GTID 事务被复制同步。
- ON_PERMISSIVE:新产生的都是 GTID 事务,但也允许有匿名事务被复制同步。
- ON:新生成的是 GTID 事务,从库只能应用 GTID 事务。
从参数给出的有效值来看,可以使用其平滑开启 GTID 模式,OFF_PERMISSIVE
就是为平滑关闭 GTID 准备的。只有当 enforce_gtid_consistency = ON
才允许 gtid_mode
被设置为 ON
。每一次修改 gtid_mode
都会导致 binary log 发生一次切换,建议业务低峰操作。
在线开启
校验是否可以开启
首先你需要在每台实例上执行该命令,然后观察错误日志,是否有异常。业务有使用违反 GTID 一致性的语法会被记录到错误日志中,如果直接改为 ON 发现时可能已经影响到了业务。
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;
观察一段时间,确认错误日志无警告信息,即可开启该参数。
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;
开启该参数后,所有违反 GTID 一致性的 SQL 都会被拒绝。
设置 GTID_MODE
如果直接修改 GTID_MODE = ON 会报如下错误:
ERROR 1788 (HY000): The value of @@GLOBAL.GTID_MODE can only be changed one step at a time: OFF <-> OFF_PERMISSIVE <-> ON_PERMISSIVE <-> ON. Also note that this value must be stepped up or down simultaneously on all servers. See the Manual for instructions.
我们需要先设置 GTID_MODE 为 OFF_PERMISSIVE:
如刚才对该值的描述,是一个关闭 GITD 的过渡属性,执行完可快速进入下一步。
-- 该操作在主从库均执行
SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
再设置 GTID_MODE 为 ON_PERMISSIVE:
该操作依旧是一个过渡属性,其表示的则是新产生的都是 GTID 事务,但也允许有匿名事务被复制,从这个阶段开始就已经是一个正式转化的过程,但依旧是对两种事务做兼容。
-- 该操作在主从库均执行
SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
确认匿名事务回放完毕:
确保该状态值输出的匿名事务数显示为 0 只要出现过 0 即可表示转换完成。
-- 该操作在从库执行
SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';
刷新 BINLOG:
触发 BINLOG 切换,保证一个 BINLOG 文件中只包含一种事务类型。
-- 该操作仅在主库执行即可
FLUSH LOGS;
设置 GTID_MODE 为 ON:
SET @@GLOBAL.GTID_MODE = ON;
修改复制模式为 GTID
-- 停止复制
STOP SLAVE;
-- 修改为 GTID 模式
CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
-- 开启复制
START SLAVE;
-- 复制同步状态
SHOW SLAVE STATUS\G
写入配置文件
gtid_mode = on
enforce_gtid_consistency = on
总结
开启 GTID_MODE
必须设置 enforce_gtid_consistency = ON
评估该参数对业务是否有影响,非常重要。