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

MySQL GTID 复制切换前怎么检查事务是否连续

来源:17golang原创

时间:2026-09-08 10:57:07 357浏览 收藏

MySQL GTID 复制切换前,判断事务是否连续的核心不是看某个“最新编号”,而是比较来源库与候选副本的 GTID 集合。最小放行条件是:来源库的 gtid_executed 是候选副本集合的子集,GTID_SUBTRACT(source, candidate) 返回空集;同时复制线程没有报错,备份检查点也不能落后于候选副本。

要点速览
  • Seconds_Behind_Source 只能说明延迟观测结果,不能单独证明没有漏事务。
  • GTID_SUBSET 判断来源事务是否全部出现在候选副本,用 GTID_SUBTRACT 找出缺口。
  • 切换前还要检查复制线程、gtid_purged、备份 GTID 检查点和写入冻结窗口。

先把“事务连续”定义成集合关系

GTID 是按来源服务器 UUID 组织的事务集合,同一个集合里既可能有连续范围,也可能有多个 UUID 和多个区间。因此,来源端显示的最后一个数字更大,并不等于候选副本拥有来源端的全部事务;反过来,候选副本存在更大的数字,也可能只是它曾经从其他来源接收过事务。

对于单来源、单候选副本的切换,可以先把来源集合记为 S,候选副本集合记为 R

  • GTID_SUBSET(S, R) = 1:来源已经提交的事务都能在候选副本的已执行集合里找到。
  • GTID_SUBTRACT(S, R) 为空:没有发现来源相对候选副本的缺口。
  • GTID_SUBTRACT(R, S) 非空:候选副本有额外事务,必须说明它来自哪个合法通道,不能直接忽略。
MySQL GTID 来源集合与候选副本集合通过 GTID_SUBSET 和 GTID_SUBTRACT 判断缺口的静态关系
图1:看来源与候选副本两个 GTID 集合的包含关系,缺口集合是切换前最直接的连续性证据。

先记录三个检查点,再比较 GTID

不要在复制仍持续写入时只截取一个孤立值。先约定一个短暂的检查窗口,在来源端记录集合,在候选副本端记录集合,并保存同一时刻的复制状态。下面的查询只负责取证,不会修改复制配置。

-- 来源库:记录当前已经提交并被二进制日志体系追踪的 GTID 集合
SELECT @@GLOBAL.gtid_executed AS source_gtid_executed,
       @@GLOBAL.gtid_purged AS source_gtid_purged;

-- 候选副本:记录已应用集合与已从日志中清理的历史集合
SELECT @@GLOBAL.gtid_executed AS replica_gtid_executed,
       @@GLOBAL.gtid_purged AS replica_gtid_purged;

-- 候选副本:保留复制线程、自动定位和延迟字段的同一份快照
SHOW REPLICA STATUS\G

MySQL 8.4 的 SHOW REPLICA STATUS 中,重点看 Replica_IO_RunningReplica_SQL_RunningAuto_PositionSeconds_Behind_Source 以及最近错误字段。复制线程都为运行状态只是必要条件,不代表集合已经追平;延迟为零也不能替代 GTID 比较。

用两个函数找出漏事务与额外事务

把上一步保存的两个 GTID 字符串带入同一条比较语句。示例中的 UUID 和范围只是格式示例,生产环境必须替换成真实检查点,不能直接把示例结果当成当前拓扑结果。

-- 把两端在同一检查窗口取得的集合填入变量
SET @source_gtid = 'SOURCE_UUID:1-120';
SET @candidate_gtid = 'SOURCE_UUID:1-120';

-- source 是否完整包含在 candidate 中;1 才表示没有来源侧缺口
SELECT GTID_SUBSET(@source_gtid, @candidate_gtid) AS source_is_subset,
       GTID_SUBTRACT(@source_gtid, @candidate_gtid) AS missing_on_candidate,
       GTID_SUBTRACT(@candidate_gtid, @source_gtid) AS extra_on_candidate;

结果解释要保持克制:source_is_subset=1missing_on_candidate 为空,说明在这个检查点上没有发现来源相对候选副本的漏应用事务。若缺口非空,先等待复制并重新取快照;如果反复存在,再沿复制错误、过滤规则、通道来源和二进制日志保留情况排查。

extra_on_candidate 非空不一定等于数据损坏。多源复制、旧主库曾经写入、组复制切换或人为注入 GTID 都可能形成额外集合,但切换为单来源前必须有明确记录,否则新主库可能携带来源库没有的事务。

把延迟、备份和放行条件放在一张清单里

检查项通过标准不通过时怎么做
GTID 包含关系GTID_SUBSET(S,R)=1 且来源侧差集为空等待追平或排查复制缺口,不切换
复制线程IO、SQL 线程运行,最近错误为空先处理停止、重试或过滤错误
延迟观测延迟低于业务允许窗口,且与集合结果一致延长观察,不用单个延迟值强行放行
备份检查点备份记录的 GTID 集合已被候选副本包含,或有可解释的冻结顺序重新确认备份元数据与恢复目标
写入边界应用写入已冻结,或有明确的最后写入 GTID先停止写入并重新采集两端集合
MySQL GTID 切换放行清单连接来源集合、复制状态、备份检查点与写入冻结边界的静态结构图
图2:切换判断需要同时覆盖 GTID 集合、复制状态、备份检查点和写入边界,任何一个边界没有证据都不能只靠延迟值放行。

如果最近备份只保存了自己的 GTID 检查点,可以再比较 GTID_SUBSET(backup_gtid, candidate_gtid)。这只能说明候选副本包含备份对应的事务集合,不能替代恢复演练或业务级数据抽样;它的价值是把“备份时间”变成可追踪的事务边界。

常见问题

GTID_SUBSET 返回 1 就可以立刻切换吗?

不可以。它只回答集合包含关系,还要确认复制线程、最近错误、写入冻结、额外事务和备份检查点。

Seconds_Behind_Source 为 0 但 GTID 仍有缺口,为什么?

延迟字段可能只反映复制线程观测到的时间差,不能表达所有集合差异。以 GTID 差集为准,并重新取同一窗口的快照。

候选副本的 gtid_purged 比来源大怎么办?

先确认是否经历过合法的多源、旧主切换或日志清理。无法解释的额外集合应阻止切换,不能为了“看起来连续”直接修改 GTID 状态。

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