大表迁移必然引发主从延迟飙升,关键在于控制不爆:因迁移语句在从库被串行回放,单表大事务阻塞sql线程池;即使启用并行复制,涉及单表写入仍无法并发;需分批迁移、加哨兵标记、停启slave配合gtid校验,并调优从库刷盘与缓冲参数。

大表迁移必然引发主从延迟飙升,关键不是“会不会”,而是“怎么控住不爆”。
为什么 mysqldump 或 INSERT SELECT 一跑,Seconds_Behind_Master 就跳到几百秒?
本质是迁移语句在从库被串行重放:一个 INSERT INTO t_new SELECT * FROM t_old 在主库可能几秒执行完,但从库 SQL 线程必须逐行回放整个结果集,中间无法并行——尤其当 t_old 是千万级表时,这个事务会卡死整个 SQL 线程池。
常见错误现象:
-
SHOW PROCESSLIST里从库 SQL 线程长期卡在Reading event from the relay log - 监控曲线像心电图:每批迁移一发,延迟猛拉高,回落一半又来下一批
- 即使开了
slave_parallel_workers=16,只要该事务涉及单表写入,所有并行线程都会等它
用 pt-online-schema-change 迁移大表时,如何防延迟雪崩?
pt-online-schema-change 本身不锁表,但它靠触发器捕获增量,而触发器产生的 DML 在从库仍需回放。若迁移期间主库写入频繁,从库可能因触发器日志堆积 + 主表迁移语句叠加,导致延迟陡增。
实操建议:
- 迁移前先在从库执行
STOP SLAVE,导出快照或完成首批数据后,再START SLAVE,避免 binlog 积压 - 用
--chunk-size=1000控制每次拷贝行数,配合--sleep=0.1给从库喘息时间 - 禁用
--statistics类调试参数,减少额外 IO;把--max-load设为从库真实负载阈值(如Threads_running=20) - 迁移过程中持续轮询
Seconds_Behind_Master,一旦 >30 秒,立即暂停下一批
分批次迁移时,怎么让每批都“可等待、可回滚、可过滤”?
不能只靠 SHOW MASTER STATUS 记 position——GTID 模式下 position 不可复现,级联复制下更不可信。
必须做到三件事:
- 每批开始前,执行
SELECT @@global.gtid_executed;并存档;同时插入带唯一标记的哨兵记录,如INSERT INTO _migrate_log (batch_id, ts) VALUES ('20260904_001', NOW()); - 每批执行后,用
SELECT MASTER_POS_WAIT()或轮询Seconds_Behind_Master = 0,确认从库已追平才发下一批 - 所有迁移 DML 必须加
WHERE migrate_batch_id = '20260904_001'类条件,紧急时可用mysqlbinlog --base64-output=DECODE-ROWS | grep migrate_batch_id快速定位并跳过
从库配置上哪些改动能直接压低延迟峰值?
迁移期间从库不是“只读备胎”,而是关键承压节点。以下配置调整几乎零风险、见效快:
- 设
skip_log_bin=ON:关闭从库 binlog,避免 relay log → binlog 的二次写入放大 - 调
innodb_flush_log_at_trx_commit=2和sync_binlog=0:牺牲极小一致性换取刷盘性能,仅限迁移窗口期 - 增大
relay_log_space_limit(如设为 8G):防止大批量迁移触发中继日志轮转阻塞 - 确保
innodb_buffer_pool_size≥ 物理内存 70%,避免迁移扫描时频繁刷脏拖慢 SQL 线程
真正难控的从来不是工具或命令,而是每批之间的等待节奏和标记粒度——延迟爆掉往往发生在“以为追平了,其实没查准”的那几秒里。











