一、为什么需要 GTID
在传统 MySQL 主从复制中,CHANGE MASTER TO 需要指定 MASTER_LOG_FILE 和 MASTER_LOG_POS。这套机制在简单场景下运行良好,但一旦涉及故障切换,问题就暴露了:
- 主库宕机后,需要找到从库中最接近主库的那个节点,手动计算 binlog 偏移量;
- 多个从库的复制进度不一致,切换后容易出现数据丢失或重复;
- 级联复制、多源复制场景下,定位位点几乎是一场噩梦。
GTID(Global Transaction Identifier,全局事务标识符)正是为解决这些痛点而生。它让每一个事务在整个复制拓扑中拥有唯一身份,从而使故障切换从"找位点"变成"告诉从库追谁"。
二、GTID 的核心原理
2.1 GTID 的组成
一个 GTID 的格式为:
source_id:transaction_id
source_id:通常是产生该事务的源库server_uuid;transaction_id:在该源库上按事务提交顺序单调递增的序号。
例如:3f9a1b2c-4d5e-11ee-be56-0242ac120002:1-100 表示该源库上第 1 到第 100 个事务。
2.2 GTID 的生成与分配
当事务在主库提交时,MySQL 会为其分配一个 GTID,并写入 binlog。从库通过 IO_THREAD 拉取 binlog,由 SQL_THREAD 重放。重放时,从库会先检查 gtid_executed 中是否已包含该 GTID:
- 已包含:跳过,保证幂等;
- 未包含:执行事务,并将其记录到
gtid_executed。
这就实现了"每个事务在每台机器上最多执行一次"的语义。
2.3 关键参数
gtid_mode = ON
enforce_gtid_consistency = ON
log_bin = ON
log_slave_updates = ON
enforce_gtid_consistency 会禁止那些无法用 GTID 安全描述的操作,例如:
CREATE TABLE ... SELECT(在部分版本中受限);- 在事务中同时更新事务表和非事务表;
TEMPORARY TABLE与事务表的混合操作。
2.4 gtid_executed 与 gtid_purged
gtid_executed:本机已执行过的 GTID 集合,是判断数据是否已应用的核心依据;gtid_purged:本机已清除的 binlog 所对应的 GTID 集合。
两者的关系是:gtid_purged 是 gtid_executed 的子集。当从库要重放的事务落在 gtid_purged 中时,说明对应的 binlog 已被删除,复制将报错 1236。
三、基于 GTID 的复制搭建
传统方式:
CHANGE MASTER TO
MASTER_HOST='master_host',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;
GTID 方式:
CHANGE MASTER TO
MASTER_HOST='master_host',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_AUTO_POSITION=1;
MASTER_AUTO_POSITION=1 是 GTID 复制的开关。从库会把自己的 gtid_executed 发送给主库,主库据此计算出从库缺失的事务并推送。整个过程无需人工指定位点。
四、故障切换实践
4.1 切换前的判断
主库宕机后,需要选出数据最新的从库作为新主。判断依据:
-- 在候选从库上执行
SELECT @@GLOBAL.gtid_executed;
SHOW SLAVE STATUS\G
比较各从库 gtid_executed 的包含关系。若从库 A 的集合是 B 的超集,则 A 数据更新。若互不包含,说明存在分叉,需要人工介入。
4.2 切换步骤
假设选出从库 B 为新主:
-
确认 B 已追平:
SHOW SLAVE STATUS中Seconds_Behind_Master为 0,且Retrieved_Gtid_Set等于Executed_Gtid_Set。 -
在 B 上停止复制并提升为主:
STOP SLAVE; RESET SLAVE ALL; SET GLOBAL read_only = OFF; -
让其他从库指向新主:
STOP SLAVE; CHANGE MASTER TO MASTER_HOST='new_master_host', MASTER_USER='repl', MASTER_PASSWORD='password', MASTER_AUTO_POSITION=1; START SLAVE; -
处理旧主:旧主恢复后,将其作为从库接入新主。由于 GTID 的幂等性,旧主上已执行的事务会被自动跳过,不会重复应用。
4.3 常见故障与处理
错误 1236: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 在主库上已被 purge。解决方式:
- 若从库数据完整,可在从库上设置
gtid_purged跳过缺失部分(有数据丢失风险); - 更安全的做法是重新从主库做一次全量备份恢复。
错误 1062:主键冲突
通常发生在从库被误写、或切换过程中出现双写。需要检查 gtid_executed 的差异,定位冲突事务后手工修复。
五、面试高频追问
Q1:GTID 复制相比传统复制有哪些优势?
- 故障切换无需计算位点,自动化程度高;
- 每个事务全局唯一,复制具备幂等性,减少重复执行;
- 便于拓扑变更,支持多源复制、级联复制;
- 可通过
gtid_executed快速判断数据一致性。
Q2:GTID 复制下如何判断主从是否有延迟?
Seconds_Behind_Master 并不完全可靠。更准确的方式是比较主库的 gtid_executed 与从库的 Retrieved_Gtid_Set / Executed_Gtid_Set,看从库还差哪些事务。
Q3:MASTER_AUTO_POSITION=1 时,从库是如何向主库请求数据的?
从库在握手阶段发送自己的 gtid_executed 集合,主库计算差集后,从缺失的第一个事务开始推送 binlog。
Q4:GTID 模式下能否使用 sql_slave_skip_counter?
不能。GTID 模式下该参数被禁用,跳过事务需要使用 SET GTID_NEXT='xxx'; BEGIN; COMMIT; SET GTID_NEXT='AUTOMATIC'; 的方式注入空事务。
Q5:gtid_purged 设置有哪些限制?
只能在 gtid_executed 为空时设置,且设置的值不能与 gtid_executed 有交集。设置后不可回退,需谨慎操作。
六、总结
GTID 复制的本质,是把"基于位点的复制"升级为"基于事务集合的复制"。它用全局唯一标识替代了脆弱的文件偏移量,使故障切换从手工计算变为自动化流程。在生产实践中,配合 orchestrator、MHA 或 MySQL Group Replication 等工具,GTID 能显著降低切换的复杂度和出错概率。
掌握 GTID,不仅是应对面试的需要,更是构建高可用 MySQL 架构的基本功。理解 gtid_executed、gtid_purged 与 MASTER_AUTO_POSITION 三者的关系,就抓住了 GTID 复制的核心。
未经允许不得转载:任鹏个人博客 » MySQL GTID 复制原理与故障切换实战:从面试题到生产落地

