mysql跨库迁移不能只靠mysqldump,因其逻辑全量导出会锁表或阻塞写入,且无位点信息无法增量追平;必须结合binlog实时拉取+回放实现秒级停机。

MySQL跨库迁移为什么不能只靠mysqldump
因为mysqldump是逻辑全量导出,锁表或至少阻塞写入,线上库扛不住;更关键的是它不带位点信息,没法和目标库做增量追平。真正可行的在线迁移,必须依赖binlog实时拉取+回放,才能做到停机窗口控制在秒级。
用Canal还是Maxwell做binlog订阅
两者都支持MySQL binlog解析,但实际选型要看你的下游消费链路:
-
Canal是阿里系,Java写的,对接RocketMQ/Kafka成熟,但部署依赖ZooKeeper,配置项多,destination、filter.regex稍不注意就漏表 -
Maxwell更轻量,直接输出JSON到Kafka,启动快,但对GTID模式要求严格,遇到SET SESSION sql_log_bin=0写入会丢事件 - 如果目标库是MySQL,推荐用
gh-ost或pt-online-schema-change做单表迁移;跨库整体迁移,Canal兼容性更稳,尤其在5.7混合模式(ROW+STATEMENT)下容错更强
如何避免主从延迟导致数据不一致
binlog同步不是“发完就完”,中间有网络传输、解析、应用三道延迟。最常踩的坑是:没校验位点,就直接切流。
- 务必在源库执行
SHOW MASTER STATUS拿到File和Position,再比对目标端消费到的binlog位置 - Canal里看
client-adapter日志里的lastestBinlogOffset,不是看Kafka lag - 切库前强制打一个
FLUSH LOGS,让binlog切新文件,再等目标端追平这个新文件的起始position - 不要依赖
Seconds_Behind_Master——那是从库IO线程的延迟,不是你自建同步链路的延迟
DDL变更怎么安全同步到目标库
binlog里DDL语句默认不记录表结构变更细节,CREATE TABLE能同步,但ALTER TABLE ADD COLUMN可能被跳过或报错,尤其跨版本(如5.7→8.0)。
- Canal开启
supportDDL=true,并确保filter.regex没把information_schema相关库过滤掉(否则无法获取元数据) - Maxwell必须配合
--include-ddl参数,且源库binlog_format=ROW,否则DDL直接不捕获 - 强烈建议把DDL单独拎出来人工review:先在目标库执行
SHOW CREATE TABLE比对字段类型、默认值、注释是否一致,特别是TINYINT(1)和BOOLEAN这种隐式转换
真正难的不是跑通同步,而是确认“哪一行数据在哪个时刻、以什么格式、被哪条SQL改过”。位点对齐、DDL兼容、字符集隐式转换这三处,随便漏一个,上线后查半天才发现少了一列或时间戳全乱了。











