核心答案:Seconds_Behind_Master=0不可信,因并行复制下事务可能滞留coordinator队列,GTID模式下必须校验Retrieved_Gtid_Set等于Executed_Gtid_Set。

MySQL升级过程中主库无损切换,核心不是“能不能切”,而是“切之前数据是否真正追平、切之后写入是否被正确承接”。单纯等 Seconds_Behind_Master = 0 就切,90% 的线上事故都出在这一步。
为什么 Seconds_Behind_Master = 0 不可信?
并行复制(slave_parallel_workers > 0)下,SQL线程可能已执行完 relay log,但部分事务仍在 coordinator 队列中未调度——此时 Seconds_Behind_Master 显示为 0,实际延迟隐性存在。更危险的是,GTID 模式下 Executed_Gtid_Set 和 Retrieved_Gtid_Set 差值为 0 才代表日志收全,仅看延迟值毫无意义。
- 必须检查
SHOW SLAVE STATUS\G中的Retrieved_Gtid_Set是否等于Executed_Gtid_Set - 若使用非 GTID 模式,需比对
Relay_Master_Log_File和Exec_Master_Log_Pos与主库SHOW MASTER STATUS的File/Position -
Slave_SQL_Running_State必须是Slave has read all relay log; waiting for more updates,而非Reading event from the relay log
升级前必须执行的 4 个验证动作
这四步缺一不可,跳过任意一项都可能在升级后出现主键冲突、丢失更新或回滚失败:
- 在从库执行
SELECT MASTER_POS_WAIT('mysql-bin.000012', 123456789, 10),返回值必须为0(注意:参数要和主库当前SHOW MASTER STATUS输出严格一致) - 主库执行
FLUSH TABLES WITH READ LOCK后,**立刻**在从库执行同表COUNT(*)对比,误差必须为 0(锁只持几秒,务必抢在锁释放前查) - 确认从库
read_only = ON且super_read_only = ON(防止 SUPER 权限用户绕过写入) - 检查所有触发器、事件、存储过程是否兼容新版本语法(尤其 5.7 → 8.0 升级时
sys库变更、密码策略、关键字保留字)
切换瞬间的关键操作顺序(GTID 模式)
顺序错一步,就可能让新主库写入后无法被其他从库同步,或导致 GTID 集合断裂:
- 主库执行:
FLUSH TABLES WITH READ LOCK→ 立即记录SELECT @@global.gtid_executed - 从库执行:
STOP SLAVE→SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS('a-b-c-123', 10)(等待刚才记录的 GTID 集合完全执行) - 从库执行:
SET GLOBAL read_only = OFF→RESET SLAVE ALL(清除复制元数据,避免残留master_info_repository干扰) - 主库保持
read_only = ON不关闭,仅释放锁:UNLOCK TABLES(留作 5 分钟内回切兜底)
DNS 和连接池带来的“假切换成功”
数据库 IP 切换完成 ≠ 应用已连上新主。真实故障常发生在切换后 2–3 分钟,表现为写请求超时或报错 ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement——说明部分实例还在连旧主。
- DNS TTL 必须提前设为 ≤ 30 秒,且应用侧需禁用 JVM DNS 缓存(
java.security.Security.setProperty("networkaddress.cache.ttl", "30")) - HikariCP/Druid 连接池必须开启
connection-test-query = SELECT 1和connection-init-sql = SET SESSION wait_timeout=28800,否则空闲连接会持续复用旧连接 - 禁止在应用配置里硬编码 IP,必须走 VIP、ProxySQL 或服务发现(如 Nacos/ZK)
最易被忽略的点:升级后首次写入前,务必在新主库执行 SELECT @@version 和 SELECT @@gtid_mode 双重确认;很多事故源于从库升级失败但进程未退出,伪装成正常节点参与切换。


















