主从复制不能直接用于零停机迁移。它缺乏连接切换、DDL阻塞处理、角色转换和GTID一致性校验能力;GTID必须主从均启用并校验;从库需临时关闭read_only;应以GTID差集而非Seconds_Behind_Master判断追平;应用切流须双写+原子开关兜底。

不能直接把主从复制当迁移方案用。它只是数据同步机制,不处理连接切换、DDL阻塞、角色转换或GTID一致性校验——这些才是零停机迁移真正卡点。
GTID必须开,且主从两端同时生效
没开gtid_mode=ON和enforce_gtid_consistency=ON,切流后无法可靠定位事务位置,一写就错。别只在主库配,从库也得同步改配置并重启。检查方式是执行SHOW VARIABLES LIKE 'gtid%',两边都得返回ON。如果中途发现某台从库gtid_mode为OFF,立刻停操作,否则后续CHANGE MASTER TO会因GTID不一致失败。
从库只读必须临时关闭,且仅限切换窗口期
从库默认read_only=ON,但应用直连后执行写语句会报ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement。切流前需在从库执行SET GLOBAL read_only = OFF,但切完新主库流量后必须立刻执行SET GLOBAL read_only = ON,否则可能被误写污染数据。注意:该操作不持久,重启后恢复原值,所以不能依赖它长期维持可写状态。
别信Seconds_Behind_Master,用GTID差集判断真实追平
Seconds_Behind_Master在并行复制下经常显示0,实际SQL线程还在积压。正确做法是对比Retrieved_Gtid_Set和Executed_Gtid_Set:
SELECT
GTID_SUBTRACT(
(SELECT Retrieved_Gtid_Set FROM performance_schema.replication_connection_status),
(SELECT Executed_Gtid_Set FROM performance_schema.replication_applier_status_by_coordinator)
) AS pending_gtids;
返回空集合''才代表真正追平。也可以用SELECT MASTER_POS_WAIT('mysql-bin.000001', 123456789, 2)做超时等待,但前提是主库位点已知且稳定(适用于切换前最后一次确认)。
应用层切流必须带双写兜底和原子开关
DNS或VIP切换太慢,客户端缓存会导致部分请求打到旧主库。稳妥做法是分三步走:
- 先让新从库承担全部读流量(确认
Slave_SQL_Running = Yes且pending_gtids为空) - 上线一个开关(如Redis key
migration:write_target),初始值为old;所有写请求先发旧主,再异步发新主(用INSERT ... ON DUPLICATE KEY UPDATE或幂等日志保证重试不重复) - 校验新主数据一致后,原子性地把开关设为
new,旧主停止写入;5分钟内紧盯错误日志,出现Deadlock found when trying to get lock或Lock wait timeout exceeded说明双写还没收敛完,得回退
真正难的从来不是START SLAVE跑起来,而是确认「此刻从库的数据,就是主库当前时刻该有的样子」——这个“时刻”必须由GTID精确锚定,而不是靠时间戳或秒数估算。


















