登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL GTID_EXECUTED 怎样判断复制位点是否推进

来源:17golang原创

时间:2026-11-02 05:48:11 490浏览 收藏

MySQL 复制排查时,很多人看到 GTID_EXECUTED 里最后一个数字变化,就把它当成“复制位点已经推进”。这个判断不够稳:GTID_EXECUTED 实际是一个 GTID 集合,可能包含多个 UUID、连续区间和已经保留的历史事务。可靠做法是同时读取源端与副本端的集合,再判断集合覆盖关系。

官方文档:https://dev.mysql.com/doc/refman/8.4/en/replication-gtids.html

本文只解决一个问题:怎样根据 GTID 集合判断副本是否追上源端,以及没有追上时缺了哪些事务。示例使用 MySQL 8.4 语法,命令中的输出是说明格式,不代表某台机器的实际运行结果。

判断复制位点是否推进,不要只看单个序号;先取源端集合 S 和副本端集合 R,再用 GTID_SUBSET(R,S)、GTID_SUBTRACT(S,R) 判断覆盖关系和缺口。

先弄清 GTID_EXECUTED 到底表示什么

全局变量 @@GLOBAL.gtid_executed 表示服务器已经执行过的 GTID 集合;在源端执行 SHOW BINARY LOG STATUS 时,Executed_Gtid_Set 表示同一类信息。在副本端执行 SHOW REPLICA STATUS 时,也能看到 Executed_Gtid_Set。

因此它不是传统复制里的 File 加 Position,也不是一个可以简单做减法的整数。下面这样的集合:

3e11fa47-71ca-11e1-9e33-c80aa9429562:1-120
3e11fa47-71ca-11e1-9e33-c80aa9429562:125-130

中间的 121-124 可能并不在集合里。多源复制、过滤规则或事务执行顺序变化时,集合还可能包含多个 UUID。先把它当集合处理,后面的判断才不会被“最后一个数字”误导。

源端与副本端 GTID 集合、执行集合和复制状态字段的静态关系说明图
图1:GTID 集合关系说明图,展示源端与副本端的执行集合、接收集合和传统位置字段各自承担的职责。

先分别保存源端和副本端快照

排查时不要在两个终端之间凭感觉对照。先在源端保存执行集合,再在副本端同时保存执行集合、接收集合和线程状态。这样可以区分“还没收到”和“已经收到但还没应用”。

-- 源端:查看已经执行并写入二进制日志的 GTID 集合
SHOW BINARY LOG STATUS\G

-- 副本端:同时查看已接收、已应用以及线程状态
SHOW REPLICA STATUS\G

-- 副本端:只取全局执行集合,便于脚本采集
SELECT @@GLOBAL.gtid_executed AS replica_executed;

源端关注 Executed_Gtid_Set,副本端关注 Executed_Gtid_Set 与 Retrieved_Gtid_Set。Retrieved_Gtid_Set 只说明事务已经进入或曾经进入 relay log,并不等于 SQL applier 已经执行完成。

如果 Retrieved_Gtid_Set 比副本的 Executed_Gtid_Set 更大,说明接收线程已经走在前面,应用线程仍有追赶空间;如果两者接近但线程状态异常,则应转向复制错误、权限或过滤规则排查。

用集合函数判断“是否追上”

假设源端快照记为 S,副本端已执行集合记为 R。MySQL 的 GTID_SUBSET(set1,set2) 在 set1 的所有 GTID 都包含于 set2 时返回 1,所以最直接的覆盖判断是:

-- 把下面两个字符串替换为同一时间窗口采集的源端与副本端集合
SET @source_set = '3E11FA47-71CA-11E1-9E33-C80AA9429562:1-130';
SET @replica_set = '3E11FA47-71CA-11E1-9E33-C80AA9429562:1-120';

-- 副本集合覆盖源端集合时才可认为当前集合已追平
SELECT GTID_SUBSET(@source_set, @replica_set) AS source_covered;

-- 反向差集用于找出源端有而副本端没有的事务
SELECT GTID_SUBTRACT(@source_set, @replica_set) AS missing_on_replica;

当 source_covered 为 1 时,副本的已执行集合覆盖了源端快照;当结果为 0 时,查看 missing_on_replica。例如差集为 ...:121-130,就表示这段事务仍未出现在副本的已执行集合中。

反向再算一次也很有用:

-- 如果副本集合反过来多出事务,说明两边可能不是同一复制拓扑或存在额外来源
SELECT GTID_SUBTRACT(@replica_set, @source_set) AS extra_on_replica;

这个结果不应被简单解释成“副本错误”。多源复制、切换过源库、人工注入 GTID 或采集时间不同,都可能让副本集合包含源端快照没有的事务。

GTID_SUBSET 与 GTID_SUBTRACT 比较源端集合和副本集合的静态判断关系图
图2:集合比较说明图,展示覆盖判断、源端缺口和副本额外集合三种结果的关系。

线程状态决定“没推进”属于哪一层

集合比较只回答事务是否已经执行,不能单独说明复制为什么没有推进。副本端还要一起看 Replica_IO_Running、Replica_SQL_Running、Last_IO_Error 和 Last_SQL_Error。

  • 接收集合不变,IO 线程异常:优先检查网络、账号权限、源端连接和 TLS 配置。
  • 接收集合增加,执行集合不变:优先查看 SQL 线程、错误信息、锁等待和复制过滤。
  • 两个集合都在增加但仍有差集:复制正在推进,差集应作为当前延迟范围,连续采样后再判断是否停止。
  • 多通道复制:不要只看一个默认通道的状态;集合是服务器级视角,通道级故障仍需按 SHOW REPLICA STATUS 的 Channel_Name 分开记录。

生产环境中建议连续取两次快照,例如间隔几秒或一个业务采样周期。一次快照只能说明瞬时集合关系,连续快照才能说明集合是否继续增长。不要把 Seconds_Behind_Source 单独当成 GTID 一致性的证明。

最小排查清单

  1. 源端记录 SHOW BINARY LOG STATUS 的 Executed_Gtid_Set。
  2. 副本端记录 SHOW REPLICA STATUS 的 Retrieved_Gtid_Set、Executed_Gtid_Set 和线程状态。
  3. 用 GTID_SUBSET(S,R) 判断源端集合是否被副本覆盖。
  4. 用 GTID_SUBTRACT(S,R) 输出缺口,用反向差集识别额外来源。
  5. 连续采样后再处理网络、SQL 错误、过滤规则和多通道问题。

一句话总结:GTID_EXECUTED 适合做集合级的复制进度判断,不适合被压缩成一个“最后位点数字”。先区分已接收与已执行,再用集合覆盖和差集定位,结论才可用于生产排查。

相关问题

GTID_EXECUTED 为空是不是复制失败?

不一定。先确认 GTID 是否启用、当前服务器是否执行过 GTID 事务,以及查询的是全局变量还是某个复制通道。若 GTID 未使用,相关集合本来就可能为空。

为什么副本的 Retrieved_Gtid_Set 已经变大,Executed_Gtid_Set 还没变?

通常表示接收线程已经收到事务,但应用线程尚未完成执行。应结合 SQL 线程状态和 Last_SQL_Error 判断是正常追赶、锁等待还是应用错误。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>