一、GTID 是什么?
GTID(全局事务 ID)
是 MySQL 5.6 及以上版本引入的全局唯一的事务标识,格式为:GTID = source_id:transaction_id
source_id
:生成该事务的主库唯一标识(即主库的server_uuid
,自动生成,不会重复)transaction_id
:该事务在主库上的 “自增序号”(主库每执行一个事务,序号 + 1,从 1 开始)
关键特性:一个事务在整个复制集群中(主库、所有从库)只有一个
GTID,且永久唯一
(即使主从切换,历史事务的 GTID 也不会变)
二、GTID 复制的核心原理
传统复制的核心是 “主库记日志,从库按‘文件 + 位置’找日志”
,而 GTID 复制的核心是 “按事务 ID 复制”
1. 传统复制的缺点
传统复制依赖 “二进制日志文件(如 mysql-bin.000004
)+ 日志位置(如 125
)” 定位事务,流程是:
主库执行事务,写入二进制日志(记为 “文件 A: 位置 X”)
从库通过
CHANGE MASTER TO MASTER_LOG_FILE='文件A', MASTER_LOG_POS=X
指定要同步的起点从库读取主库的二进制日志,按 “文件 + 位置” 顺序执行。
缺点:
主从切换后,新主库的日志文件和位置与旧主库无关,从库需重新找 “新主库的文件 + 位置”,极易出错
若主库日志文件轮转(如
mysql-bin.000004 满了生成 000002
)从库若未及时同步,可能漏读日志排查复制延迟时,无法快速定位 “哪个事务没同步”
2. GTID 复制的核心流程
GTID 复制通过 “事务 ID 绑定”,让从库不再依赖 “文件 + 位置”,而是直接追踪 “未执行的 GTID”
步骤 1:主库生成 GTID 并记录事务
主库执行一个事务时,会先检查自己的 gtid_executed
(已执行的 GTID 集合),生成一个新的 transaction_id
(自增),与自身 server_uuid
组成 GTID
事务执行成功后,会将 GTID + 事务内容 一起写入二进制日志(binary log)
同时,主库会更新自身的
gtid_executed
(添加这个新 GTID)
步骤 2:从库获取 GTID 并定位 “待执行事务”
从库的 IO 线程(负责拉取主库日志)会从主库读取二进制日志,将日志写入本地的中继日志(relay log)
从库会先解析中继日志中的 GTID,对比自己的
gtid_executed
(已执行的 GTID)和gtid_purged
(已删除的 GTID)若该 GTID 不在
gtid_executed
中,说明是 “待执行事务”,从库会标记这个 GTID 为 “待处理”
步骤 3:从库执行事务并更新 GTID 状态
从库的 SQL 线程(负责执行中继日志)会按顺序执行 “待处理” 的 GTID 对应的事务:
执行前,从库会先检查该 GTID 是否已执行(避免重复执行,解决传统复制的 “重复同步” 问题);
执行成功后,从库会更新自己的
gtid_executed
(添加该 GTID),并继续处理下一个 GTID。
3. 核心逻辑总结
GTID 复制本质是 “事务级别的追踪”:
主库用 GTID 给每个事务 “打标签”;
从库用 GTID 筛选 “自己没执行过的事务”;
整个复制过程围绕 “GTID 集合” 的同步展开,而非 “日志文件的位置”。
三、GTID 复制的核心优势(对比传统复制)
GTID 复制的优势完全针对传统复制的痛点,可通过表格直观对比:
对比维度 | 传统复制(文件 + 位置) | GTID 复制(事务 ID) |
---|---|---|
主从切换 | 需手动找新主库的 “日志文件 + 位置”,易出错 | 自动定位:从库直接用新主库的 gtid_executed 同步,无需手动指定位置 |
事务重复执行 | 可能重复执行(如从库重启后) | 绝对避免:通过 gtid_executed 检查,已执行的 GTID 不重复跑 |
复制故障排查 | 需对比日志文件和位置,效率低 | 直接查看 gtid_executed ,快速定位 “未同步的 GTID” |
集群扩展(新增从库) | 需找主库的 “日志文件 + 位置” 作为起点 | 新增从库自动同步主库的 gtid_executed ,无需手动指定起点 |
复制安全性 | 可能漏读日志(如文件轮转) | 基于 GTID 集合,确保事务不丢、不重 |
四、GTID 复制的实操步骤(MySQL 8.0 为例)
GTID 复制的配置核心是 “开启 GTID 模式”+“指定复制参数”,步骤如下(假设主库 IP:192.168.1.100,从库 IP:192.168.1.101):
前提条件
主库和从库的 MySQL 版本 ≥ 5.6(推荐 8.0,兼容性更好);
主库和从库的
server_uuid
必须不同(MySQL 自动生成,若克隆机器需删除auto.cnf
重新生成);主库已开启二进制日志(
log_bin
已配置)。
步骤 1:配置主库(my.cnf)
[mysqld]
# 1. 开启二进制日志(主库必开)
log_bin = mysql-bin
server_id = 100 # 主库唯一ID(整数,与从库不同)
# 2. 开启GTID模式(核心参数)
gtid_mode = ON # 强制开启GTID
enforce_gtid_consistency = ON # 确保事务与GTID兼容(禁止不支持GTID的操作,如CREATE TABLE ... SELECT)
# 3. 可选:优化复制(避免从库漏读日志)
binlog_format = ROW # 推荐行模式(复制更安全,避免SQL_mode差异导致的问题)
log_slave_updates = ON # 从库执行事务后,也写入自己的二进制日志(主从切换时,新主库有完整日志)
配置后重启主库:
systemctl restart mysqld
(更新配置)
步骤 2:主库创建复制账号并授权
登录主库 MySQL,创建一个仅用于复制的账号(如 repl
),并授予 REPLICATION SLAVE
权限:
# 登录主库
mysql -u root -p '123'
# 创建复制账号(允许从库192.168.1.101连接)
CREATE USER 'repl'@'192.168.1.101' IDENTIFIED BY 'YourPassword123!';
# 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.101';
# 刷新权限
FLUSH PRIVILEGES;
步骤 3:配置从库(my.cnf/my.ini)
[mysqld]
# 1. 从库无需开二进制日志(但主从切换需开,建议提前配置)
log_bin = mysql-bin
server_id = 101 # 从库唯一ID(与主库100不同)
# 2. 开启GTID模式(与主库一致)
gtid_mode = ON
enforce_gtid_consistency = ON
# 3. 可选:优化复制
binlog_format = ROW
log_slave_updates = ON
read_only = ON # 从库设为只读(避免误写,超级用户root仍可写,8.0可设super_read_only=ON)
配置后重启从库:systemctl restart mysqld
。
步骤 4:从库开启 GTID 复制
登录从库 MySQL,执行 CHANGE MASTER TO
指定主库信息,并开启复制(核心
:无需指定日志文件和位置):
-- 登录从库
mysql -u root -p '123'
-- 1. 停止现有复制(若之前有传统复制,需先停)
STOP SLAVE;
-- 2. 配置主库信息(GTID模式核心参数)
CHANGE MASTER TO
MASTER_HOST = '192.168.1.100', # 主库IP
MASTER_USER = 'repl', # 复制账号
MASTER_PASSWORD = 'YourPassword123!', # 复制密码
MASTER_AUTO_POSITION = 1; # 开启GTID自动定位(关键!无需指定log_file和log_pos)
-- 3. 启动从库复制线程
START SLAVE;
步骤 5:验证 GTID 复制是否成功
在从库执行以下命令,检查复制状态:
-- 查看从库状态(核心看两个线程是否为Yes,以及GTID相关参数) SHOW SLAVE STATUS\G;
关键验证点:
Slave_IO_Running: Yes
(IO 线程正常,能拉取主库日志)Slave_SQL_Running: Yes
(SQL 线程正常,能执行中继日志)Retrieved_Gtid_Set
:从库已拉取的 GTID 集合(应包含主库的 GTID)Executed_Gtid_Set
:从库已执行的 GTID 集合(若与Retrieved_Gtid_Set
一致,说明无延迟)
五、常见问题与注意事项
为什么执行
CREATE TABLE ... SELECT
会报错? 因为enforce_gtid_consistency = ON
时,该语句会被拆分为 “创建表” 和 “插入数据” 两个事务,但 GTID 要求一个语句对应一个事务,所以禁止。解决方案:拆分为CREATE TABLE
和INSERT ... SELECT
两个语句。主从切换后,新从库如何同步? 旧从库升级为新主库后,其他从库只需执行:
新主库会自动通过STOP SLAVE; CHANGE MASTER TO MASTER_HOST = '新主库IP', MASTER_USER = 'repl', MASTER_PASSWORD = 'YourPassword123!', MASTER_AUTO_POSITION = 1; START SLAVE;
gtid_executed
告知从库 “已执行的事务”,从库直接同步未执行的 GTID。如何跳过一个错误的 GTID 事务? 若从库执行某个 GTID 报错(如主库有从库没有的表),可手动跳过该 GTID:
-- 假设要跳过的GTID是:3E11FA47-71CA-11E1-9E33-C80AA9429562:10 SET GTID_NEXT = '3E11FA47-71CA-11E1-9E33-C80AA9429562:10'; BEGIN; COMMIT; -- 空事务,标记该GTID为已执行 SET GTID_NEXT = 'AUTOMATIC'; -- 恢复自动复制 START SLAVE;
总结
GTID 复制的核心是 “用全局唯一的事务 ID 替代文件 + 位置”,解决了传统复制的 “主从切换难、排查慢、易出错” 问题,是 MySQL 高可用集群(如 MGR)的基础。实操时只需确保 “主从、GTID 模式一致”+“从库开启自动定位”,即可实现高效、可靠的复制。