主从切换后事务丢失的根本原因在于未确认从库真正执行完毕,seconds_behind_master=0仅为假象,唯有retrieved_gtid_set与executed_gtid_set完全相等且slave_io_running、slave_sql_running均为yes,才能确保gtid模式下无事务丢失。

主从切换后从库事务丢失,不是因为没“切”,而是因为没确认它真执行完了——Seconds_Behind_Master = 0 是假象,Executed_Gtid_Set 才是真相。
为什么 SHOW SLAVE STATUS 显示 0 却还丢事务
MySQL 的 Seconds_Behind_Master 只反映 SQL 线程“预计还要多久追上 IO 线程”,不反映 relay log 是否已全部 apply。常见误导场景:
- SQL 线程卡在锁等待、DDL 阻塞或大事务回放中,IO 线程早已停住,
Seconds_Behind_Master却显示 0 - 从库开启了
read_only = ON,但 SQL 线程异常退出(如 GTID 冲突),Slave_SQL_Running变为No,而监控只看Seconds_Behind_Master忽略了该状态 - 使用
MIXED或STATEMENTbinlog 格式时,某些语句被降级为语句复制,从库执行失败但未报错(尤其跨引擎操作)
真正可信的指标只有两个:Slave_IO_Running = Yes 且 Slave_SQL_Running = Yes,且 Retrieved_Gtid_Set = Executed_Gtid_Set(GTID 模式下)。
GTID 模式下必须验证的三个值
切主前不手动比对这三项,等于闭眼升主:
- 在从库执行
STOP SLAVE后,查SELECT @@global.gtid_executed;,与主库该值逐字符比对——注意:必须停 SQL 线程再查,否则值会动态变化 - 查
SHOW SLAVE STATUS\G中的Retrieved_Gtid_Set和Executed_Gtid_Set,二者必须完全相等;若不等,说明 relay log 有积压,START SLAVE SQL_THREAD追完再验 - 执行
SELECT * FROM mysql.gtid_executed;,检查是否有某source_uuid对应的事务序列存在“空洞”(例如1-10,12-20缺了 11),这种断点意味着事务已被跳过,不可用于升主
任何一项不满足,都说明该从库已处于“逻辑损坏”状态,强行切主必然丢数据。
半同步配置失效的典型表现
开了 rpl_semi_sync_master_enabled = ON 不代表事务就安全了。以下情况会让半同步形同虚设:
-
Rpl_semi_sync_master_clients始终为 0:主库没装rpl_semi_sync_master插件,或从库没装rpl_semi_sync_slave插件,或装反了(比如从库装了 master 插件) -
Rpl_semi_sync_master_no_tx > 0:表示已有事务因超时(默认 10 秒)退化为异步提交,此时Rpl_semi_sync_master_status仍显示ON,极具欺骗性 - 从库只执行
START SLAVE,没执行STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;:插件依赖 IO 线程上报 ACK,SQL 线程不参与,不重启 IO 线程,ACK 永远不会发出去
验证方式不是看变量,而是查状态:SHOW STATUS LIKE 'Rpl_semi_sync%'; 中的 Rpl_semi_sync_master_yes_tx 应持续增长,Rpl_semi_sync_master_no_tx 应长期为 0。
切换后立刻验证新主是否真能写入
升主只是第一步,新主能否正确接受并落盘后续事务,才是数据不丢的最后一道关卡:
- 切完立刻在新主执行:
SET GLOBAL read_only = OFF;(如果之前为只读),再执行一条带 GTID 的简单事务:CREATE TABLE test_switch (id INT) ENGINE=InnoDB; - 立即查新主的
SELECT @@global.gtid_executed;,确认新增了新的 GTID;再查任意一个原从库的Executed_Gtid_Set,确认它开始同步这个新 GTID - 检查新主的
sync_binlog = 1和innodb_flush_log_at_trx_commit = 1是否生效——这两个参数一旦为 0 或 2,即使切换成功,新主自身也会丢事务
最容易被忽略的是:切换脚本里只改了 read_only,却忘了确认 binlog 和 redo 的刷盘策略是否严格开启。没有这两项,所谓“不丢失”只是把风险从主库转移到了新主库。











