在MySQL 8.0里,GTID(全局事务标识)复制能够为主从架构提供自动故障切换与便捷的重放位点管理。与早期版本不同,8.0支持在不重启数据库服务的情况下,通过动态修改系统变量逐步开启GTID模式。这种方式对线上业务极其友好,因为无需停写或中断复制链路。理解其背后的渐进式状态机设计,是安全实施的前提。

一、GTID模式与一致性约束的基本原理
MySQL的gtid_mode并非简单的开或关,而是包含四个状态:OFF、OFF_PERMISSIVE、ON_PERMISSIVE、ON。OFF表示完全不使用GTID;OFF_PERMISSIVE表示新事务不使用GTID但允许接收带GTID的事务;ON_PERMISSIVE则反过来,新事务使用GTID但允许接收匿名事务;ON是彻底只使用GTID。这样的设计是为了让主从节点在切换过程中互不中断,避免因为模式不一致导致复制报错。
另一个关键变量是enforce_gtid_consistency,它控制是否禁止会产生非GTID一致性的语句,例如涉及非事务引擎的多引擎事务、CREATE TABLE SELECT等。在开启GTID前,必须将该变量设为ON,否则后续切换会被拒绝。MySQL 8.0允许在线修改这两个变量,但状态跃迁必须按顺序进行,不能从OFF直接跳到ON。
1.1 为什么需要渐进切换
如果主库突然只发GTID事务,而从库还在OFF模式,从库会因无法识别GTID事件而中断。渐进模式让双方都有窗口期兼容对方的事务类型。比如主库先进入OFF_PERMISSIVE,从库也进入相同状态,此时主库旧连接仍可写匿名事务,新连接写GTID事务,从库都能处理。随后双方再进入ON_PERMISSIVE,最后统一ON,实现平滑过渡。
这种机制依赖于后台线程对匿名事务残留数量的统计。系统提供了Ongoing_anonymous_transaction_count等状态变量,运维人员必须观察它归零后才推进下一步,否则可能丢失匿名事务的回放。
二、在线开启GTID的完整步骤
假设已有一主一从的传统基于位点复制环境,MySQL版本均为8.0,且业务表均使用InnoDB。下面给出具体指令顺序,所有操作均通过MySQL客户端执行,不需要重启服务。
2.1 设置强制GTID一致性
在主从节点分别执行以下命令,开启一致性强制。该操作在线生效,但要求当前没有违反一致性的语句在运行。
-- 主库与从库均执行 SET GLOBAL enforce_gtid_consistency = ON; -- 确认生效 SHOW VARIABLES LIKE 'enforce_gtid_consistency';
若返回值为ON,说明设置成功。如果报错,需检查是否有会话正在执行CREATE TABLE SELECT等语句,待其结束后再试。此变量一旦开启,后续写操作若违反GTID一致性会被直接拒绝,从而保障数据安全。
需要强调的是,在业务低峰期执行更稳妥,虽然不要求停服,但突发的大量违反一致性的批量作业可能引起应用报错,应提前通知研发侧避免此类SQL。
2.2 主从依次进入OFF_PERMISSIVE
先将主库切换为OFF_PERMISSIVE,再将从库切换。顺序不强制,但建议主先于从,以便观察兼容性。
-- 主库 SET GLOBAL gtid_mode = OFF_PERMISSIVE; -- 从库 SET GLOBAL gtid_mode = OFF_PERMISSIVE; -- 查看模式 SHOW VARIABLES LIKE 'gtid_mode';
此时主库新事务仍不带GTID,但允许复制线程应用带GTID的事件(虽然此时从库也没发)。这一步主要是为下一步打基础,几乎无业务感知。可通过SHOW STATUS LIKE 'Ongoing_anonymous_transaction_count'观察匿名事务数,理想情况下很快为0。
若发现该计数持续不降,说明有长事务或未提交的连接在写匿名事务,应排查源头。只有确认无匿名事务堆积,才能继续。
2.3 切换至ON_PERMISSIVE并等待匿名事务清零
同样主从分别执行,将从OFF_PERMISSIVE提升到ON_PERMISSIVE。
SET GLOBAL gtid_mode = ON_PERMISSIVE; -- 主从均执行后,在从库观察 SHOW STATUS LIKE 'Ongoing_anonymous_transaction_count';
进入ON_PERMISSIVE后,主库新事务开始携带GTID,但从库仍兼容匿名事务。此时必须反复查询上述状态,直到值为0,代表历史匿名事务已全部复制完毕。这一步耗时取决于之前业务量,可能几秒也可能几分钟。
只有彻底清零,才能最后设为ON,否则剩余匿名事务在ON模式下无法被从库应用,造成复制中断和数据不一致。这是在线开启中最容易遗漏的等待环节。
2.4 最终开启GTID模式
确认匿名事务计数归零后,主从均执行以下命令:
SET GLOBAL gtid_mode = ON; -- 验证 SHOW VARIABLES LIKE 'gtid_mode';
此时复制链路自动转为GTID模式,从库使用Retrieved_Gtid_Set与Executed_Gtid_Set进行位点管理。可通过SHOW REPLICA STATUSG(8.0中SHOW SLAVE STATUS已废弃)查看Auto_Position是否为1,确认GTID复制已生效。
为持久化配置,应将上述变量写入配置文件,防止重启后回落。示例如下:
[mysqld] gtid_mode=ON enforce_gtid_consistency=ON
三、注意事项与常见误区
不少工程师误以为只要执行SET GLOBAL gtid_mode=ON即可,结果触发报错“Cannot switch to ON when enforce_gtid_consistency is OFF”。这是因为缺少前置一致性约束。也有人跳过OFF_PERMISSIVE直接ON_PERMISSIVE,虽不会报错,但违背了官方推荐路径,增加风险。
另一个误区是忽视多源复制或级联从库。若环境存在多级复制,每一层都必须按相同顺序独立切换,且上层进入ON前,下层必须已完成匿名事务清零。否则下级收到的GTID事件无法被上级匿名模式处理。
3.1 监控与回滚
若在ON_PERMISSIVE阶段发现严重问题,可回退到OFF_PERMISSIVE甚至OFF,只要业务未强依赖GTID。但回退时同样要等待GTID事务在从库应用完毕,避免数据丢失。在线变更的优势就是可逆,但不可逆粗心。
建议操作期间开启复制错误日志监控,并利用performance_schema.replication_applier_status表观察应用进度。任何复制异常都应暂停后续步骤,排查后再继续。
3.2 业务影响评估
整个流程对业务写入零中断,但enforce_gtid_consistency=ON会禁止特定SQL,若老系统存在CREATE TABLE SELECT报表逻辑,需提前改造。此外,切换瞬间可能有极短暂的连接元数据刷新,通常不明显。综合来看,MySQL 8.0的在线GTID开启显著降低了架构升级成本。
掌握上述步骤,运维团队便可在不重启服务的前提下,为存量集群平滑引入GTID复制,为后续自动故障转移与数据平台接入打下基础。