MySQL GTID 复制原理与故障切换实战:从面试题到生产落地

一、为什么需要 GTID

在传统 MySQL 主从复制中,CHANGE MASTER TO 需要指定 MASTER_LOG_FILEMASTER_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_purgedgtid_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 为新主:

  1. 确认 B 已追平SHOW SLAVE STATUSSeconds_Behind_Master 为 0,且 Retrieved_Gtid_Set 等于 Executed_Gtid_Set

  2. 在 B 上停止复制并提升为主

    STOP SLAVE;
    RESET SLAVE ALL;
    SET GLOBAL read_only = OFF;
    
  3. 让其他从库指向新主

    STOP SLAVE;
    CHANGE MASTER TO
      MASTER_HOST='new_master_host',
      MASTER_USER='repl',
      MASTER_PASSWORD='password',
      MASTER_AUTO_POSITION=1;
    START SLAVE;
    
  4. 处理旧主:旧主恢复后,将其作为从库接入新主。由于 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 复制的本质,是把"基于位点的复制"升级为"基于事务集合的复制"。它用全局唯一标识替代了脆弱的文件偏移量,使故障切换从手工计算变为自动化流程。在生产实践中,配合 orchestratorMHA 或 MySQL Group Replication 等工具,GTID 能显著降低切换的复杂度和出错概率。

掌握 GTID,不仅是应对面试的需要,更是构建高可用 MySQL 架构的基本功。理解 gtid_executedgtid_purgedMASTER_AUTO_POSITION 三者的关系,就抓住了 GTID 复制的核心。

未经允许不得转载:任鹏个人博客 » MySQL GTID 复制原理与故障切换实战:从面试题到生产落地

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏