MySQL学习笔记:GTID 主从复制,从原理到实践,告别传统 Binlog+Position 的痛点


📝 本文首发于 栏轩·阁

欢迎访问阅读原文,获取更好的阅读体验。


1. 什么是 GTID?

GTID (Global Transaction Identifier,全局事务标识符)是 MySQL 5.6 引入的一项核心特性,它为每个在主库 上提交的事务生成一个全局唯一的标识符,并贯穿整个复制链路。

1.1 GTID 的格式

复制代码
GTID = source_id:transaction_id
  • source_id :发起事务的服务器 UUID(即 server_uuid,存储在 auto.cnf 中)
  • transaction_id:在该服务器上递增的序列号(从 1 开始)

示例:d2c5a7b1-3f4e-11ec-8d6a-00155d0a6c11:123

1.2 GTID 的生命周期

  1. 事务在主库提交时,分配一个 GTID
  2. GTID 随 binlog 传送给从库
  3. 从库应用该事务后,记录该 GTID 到自己的 gtid_executed 集合中
  4. GTID 在整个复制拓扑中永不重复------同一 GTID 在任何节点上最多执行一次

2. 为什么需要 GTID?------ 与传统 File+Position 对比

2.1 传统 File+Position 复制的问题

在 GTID 出现之前,MySQL 主从复制依赖三个信息:

  • binlog 文件名 (如 mysql-bin.000001)
  • binlog 偏移量 (如 157)
  • 主库的 server_id
痛点 说明
定位麻烦 从库必须精确记录主库的 File + Position,一旦出错或丢失,重建同步困难
主库切换困难 主库宕机后,新主库的 File+Position 发生变化,老从库难以找到断点继续同步
跳过事务危险 SET GLOBAL sql_slave_skip_counter 跳过 N 个事务,极易跳出不一致
不支持多线程写入 多源复制(多主一从)几乎不可行

2.2 GTID 复制的优势

优势 说明
自动定位 MASTER_AUTO_POSITION=1,从库自动计算需要同步的 GTID 集合,无需手动指定 File+Position
主从切换极简 主库宕机后,将从库提升为新主库,其他从库只需指向新主库即可自动断点续传
一致性保证 GTID 天然保证每个事务在集群内只执行一次,不会重复或遗漏
支持多源复制 一个从库可以同时从多个主库同步,因为 GTID 自带 source_id 区分来源
拓扑管理友好 可通过 gtid_executed 集合快速了解各节点的事务执行情况

2.3 对比一览表

特性 File+Position GTID
复制定位方式 文件名 + 偏移量 全局唯一事务 ID
主库切换便捷性 差(需找 File+Position) 优(自动定位)
操作复杂度 中等 低
多源复制支持 不支持 原生支持
MySQL 最低版本 3.23+ 5.6+
一致性风险 跳过事务可能不一致 自动跳过已执行事务

3. 前置知识

在学习和使用 GTID 集群之前,建议先掌握:

  • MySQL 主从复制的基本原理与配置流程
  • 使用 File+Position 方式搭建过主从集群
  • 了解 binlog 的基本概念(ROW / STATEMENT / MIXED 格式)
  • 基础的 MySQL 用户权限管理

4. GTID 配置实战

4.1 主从节点配置文件

在每个节点的 my.cnf / my.ini 中添加:

ini 复制代码
# === GTID 核心配置 ===
gtid_mode = ON
enforce_gtid_consistency = ON

# === 服务器标识(每个节点唯一)===
server_id = 1              # 主从节点的 server_id 必须不同
log_bin = mysql-bin        # 启用 binlog(从库作为 relay log,建议也开启)
binlog_format = ROW        # 推荐使用 ROW 格式,与 GTID 配合最佳
skip_slave_start = 1       # 建议开启,避免启动时自动恢复复制

# === 可选推荐配置 ===
binlog_gtid_simple_recovery = ON   # 加速 GTID 恢复(MySQL 5.7.7+ 默认开启)
log_slave_updates = ON              # 从库将接收的事务写入自己的 binlog(级联复制必需)
expire_logs_days = 7                # binlog 自动清理

注意 :enforce_gtid_consistency = ON 强制所有事务都满足 GTID 安全要求,会阻止创建临时表等非事务性操作跨事务边界。

4.2 配置参数详解

参数 说明
gtid_mode = ON 启用 GTID 模式。可选值:OFF / OFF_PERMISSIVE / ON_PERMISSIVE / ON
enforce_gtid_consistency = ON 强制 GTID 一致性,禁止非安全的语句
log_slave_updates = ON 从库将同步的事务写入自己的 binlog,级联复制必需
binlog_gtid_simple_recovery = ON 简化 GTID 恢复过程,提升重启速度

4.3 配置 GTID 升级流程(从传统模式迁移)

如果你已有 File+Position 集群,可以在线滚动升级到 GTID:

复制代码
1. 在每个节点依次执行(先从库,再主库):
   SET GLOBAL gtid_mode = OFF_PERMISSIVE;
   SET GLOBAL gtid_mode = ON_PERMISSIVE;

2. 等待所有节点完成事务同步(检查各节点 gtid_owned 为空)

3. 在每个节点依次执行:
   SET GLOBAL gtid_mode = ON;

4. 启用 enforce_gtid_consistency = ON

5. 修改 CHANGE MASTER 为 MASTER_AUTO_POSITION = 1

4.4 创建复制用户

在主库上执行:

sql 复制代码
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl123';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

4.5 从库连接主库

传统方式的连接:

sql 复制代码
CHANGE MASTER TO
  MASTER_HOST='mysql-master',
  MASTER_USER='repl',
  MASTER_PASSWORD='repl123',
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=157;

GTID 方式的连接(关键区别在于 MASTER_AUTO_POSITION = 1):

sql 复制代码
-- 停止已有的同步(如果有)
STOP SLAVE;

-- 重置从库设置
RESET SLAVE;

-- 配置主库信息,关键参数是 MASTER_AUTO_POSITION = 1
CHANGE MASTER TO
  MASTER_HOST='mysql-master',
  MASTER_USER='repl',
  MASTER_PASSWORD='repl123',
  MASTER_PORT=3306,
  MASTER_AUTO_POSITION = 1;   -- 让 GTID 自动定位
  -- MySQL 8.0 如需 caching_sha2_password,需:
  -- GET_MASTER_PUBLIC_KEY = 1;

-- 启动同步
START SLAVE;

4.6 验证复制状态

sql 复制代码
SHOW SLAVE STATUS\G

重点关注以下字段:

字段 期望值 说明
Slave_IO_Running Yes IO 线程正常连接主库拉取 binlog
Slave_SQL_Running Yes SQL 线程正常应用 relay log
Auto_Position 1 关键标志:表示已启用 GTID 自动定位
Seconds_Behind_Master 0 从库延迟(0 表示实时同步)
Retrieved_Gtid_Set 有值 已从主库获取的事务集合
Executed_Gtid_Set 有值 已在从库执行的事务集合

5. GTID 核心机制深入

5.1 gtid_executed 与 gtid_purged

sql 复制代码
-- 查看已执行的所有 GTID
SHOW VARIABLES LIKE 'gtid_executed';

-- 查看已清理的 GTID(已被 purge 的 binlog 中的事务)
SHOW VARIABLES LIKE 'gtid_purged';
  • gtid_executed :该节点上已执行过的所有 GTID 集合,持久化存储在 mysql.gtid_executed 表中
  • gtid_purged:已经被 purge 的 binlog 中包含的 GTID 集合

自动定位的原理 :

当从库执行 START SLAVE 时,会将自己的 gtid_executed 发送给主库。主库计算差值,只发送从库缺失的事务。这完全省去了人工定位 File+Position 的麻烦。

5.2 GTID 模式下的复制协议

复制代码
从库 → 主库: "我已经有这些 GTID: {uuid1:1-100, uuid2:1-50}"
主库 → 从库: "好的,你缺失 {uuid1:101-150},我发给你"

这个过程由 MASTER_AUTO_POSITION = 1 自动完成,不需要人工介入。


6. 故障切换场景分析

6.1 主库宕机:传统方式 vs GTID

传统 File+Position 切换步骤
sql 复制代码
-- 1. 找新主库的当前 binlog 位置
SHOW MASTER STATUS;
-- 结果: File: mysql-bin.000003, Position: 875

-- 2. 在其他从库上手动指向新主库
STOP SLAVE;
RESET SLAVE;
CHANGE MASTER TO
  MASTER_HOST='new-master',
  ...
  MASTER_LOG_FILE='mysql-bin.000003',   -- 手动填写
  MASTER_LOG_POS=875;                    -- 手动填写
START SLAVE;
GTID 切换步骤
sql 复制代码
-- 1. 在一台从库上停止同步
STOP SLAVE;
RESET SLAVE;

-- 2. 指向新主库,无需关心位置!
CHANGE MASTER TO
  MASTER_HOST='new-master',
  MASTER_USER='repl',
  MASTER_PASSWORD='repl123',
  MASTER_PORT=3306,
  MASTER_AUTO_POSITION = 1;   -- 自动定位!

START SLAVE;

对比可见,GTID 让主从切换从复杂的手动定位简化到只需更改 IP,大幅降低了运维复杂度。

6.2 GTID 切换的缺点

尽管 GTID 大幅简化了切换流程,但它仍然需要手动执行切换,没有自动故障检测与转移机制。解决方案:

方案 说明
MHA(Master High Availability) 经典的 MySQL 高可用方案,支持 GTID,可自动检测主库故障并提升新主库
Orchestrator 现代化的 MySQL 拓扑管理工具,提供自动化故障转移和 Web UI
InnoDB Cluster + MySQL Router MySQL 官方解决方案,基于 Group Replication,实现自动故障转移
ProxySQL 中间件层读写分离,配合自动切换可实现透明故障转移

6.3 修复复制错误

跳过单个事务(不推荐,但应急可用)
sql 复制代码
-- 查看当前出错的事务 GTID
SHOW SLAVE STATUS\G

-- 注入一个空事务来跳过
SET GTID_NEXT = 'source_id:transaction_id';
BEGIN;
COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START SLAVE;

注意:GTID 模式下严禁 使用 SET GLOBAL sql_slave_skip_counter = 1,这条语句在 GTID 模式下会直接报错。


7. 监控与管理

7.1 常用监控命令

sql 复制代码
-- 查看 GTID 运行模式
SHOW VARIABLES LIKE 'gtid_mode';

-- 查看各节点的事务执行情况
SHOW MASTER STATUS\G          -- 显示本机的 GTID 执行集合
SHOW SLAVE STATUS\G           -- 显示复制状态与 GTID 信息

-- 查看从库实际接收和执行了哪些 GTID
SELECT * FROM mysql.gtid_executed;

-- 检查是否有 GTID 不一致
SHOW VARIABLES LIKE 'gtid_owned';   -- 非空 = 有未完成事务

7.2 健康检查最佳实践

sql 复制代码
-- 检查复制是否正常(适合写入监控脚本)
SELECT
  SERVICE_STATE AS 'IO_Thread',
  LAST_ERROR_NUMBER AS 'Last_IO_Error_No',
  LAST_ERROR_MESSAGE AS 'Last_IO_Error'
FROM performance_schema.replication_connection_status\G

SELECT
  SERVICE_STATE AS 'SQL_Thread',
  LAST_ERROR_NUMBER AS 'Last_SQL_Error_No',
  LAST_ERROR_MESSAGE AS 'Last_SQL_Error'
FROM performance_schema.replication_applier_status_by_worker\G

8. 总结与建议

什么时候应该使用 GTID?

场景 推荐
新建集群 ✅ 直接使用 GTID,没有理由再使用传统方式
现有传统集群 ✅ 建议迁移到 GTID,支持在线滚动升级
需要多源复制 ✅ 必须使用 GTID,传统方式不支持
MySQL 5.6 以下版本 ❌ 需要升级到 5.6+
相关推荐
太理摆烂哥1 小时前
MySQL数据库基础
数据库·mysql
starsky762382 小时前
Agent学习——上下文工程(二)
学习
高级程序源3 小时前
springboot本地生活服务平台33399-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·小程序·flask·课程设计
Dark_Fairy3 小时前
CMeKG_tools 知识图谱项目速成教程(13课共24H)
学习
悟乙己3 小时前
AFAC2026 赛题四金融长文本 Agent竞赛学习笔记:关联技术(二)
笔记·学习·金融
夜雪一千3 小时前
如何在MySQL中实现字段级加密
android·数据库·mysql
夜雪一千3 小时前
MySQL 如何存储经纬度坐标:选型、建表、空间查询实战
android·mysql·adb
CJi0NG3 小时前
【自用】MySQL-存储引擎
数据库·mysql
我送炭你添花3 小时前
ASA原理与电子维修实战:前言 一路修来,一路学习
运维·网络·学习