myloader --resume 是唯一靠谱的离线断点方案,依赖 mydumper 导出的表级独立 SQL 文件及 metadata 快照位点实现续传,需提前建库、禁手动建表,并通过行数比对定位中断表,但不校验数据完整性且无法感知文件损坏。

myloader --resume 是唯一靠谱的离线断点方案
MySQL 离线迁移本身不依赖网络,所谓“网络中断”其实是误判——真正出问题的是 SSH 连接、终端会话或本地磁盘 I/O。离线场景下,mysqldump + mysql 管道导入完全不支持断点,失败就得重来;只有 mydumper + myloader 能靠表级文件切分和 --resume 实现可落地的续传。
关键前提:必须用 mydumper 导出,不能用 mysqldump。因为 mydumper 会为每张表生成独立 .sql 文件,并附带 metadata 记录快照位点;myloader 的 --resume 才有依据可跳过已成功导入的非空表。
- 导出时加
--chunk-filesize=64,避免单表 SQL 文件过大卡住(尤其大文本字段) - 目标库必须提前建好同名库,但不要手动建表——
myloader会自动建表并判断是否跳过 -
--resume只检查表是否存在且information_schema.tables.table_rows > 0,不校验数据完整性,这点必须人工补位
中断后怎么判断哪张表卡住了
别猜,直接查。中断发生后,先停写源库(FLUSH TABLES WITH READ LOCK),再对比源/目标两端的表行数。
执行这条命令扫一遍目标库所有表当前行数:
ls /backup/db1/*.sql | sed 's/\.sql$//' | xargs -I{} mysql -h dst -Nse "SELECT COUNT(*) FROM db1.{}"再从源库查对应值:
SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = 'db1' ORDER BY table_name;
两列一比,行数明显少于源库的表,就是中断点。常见现象:
- 某张表在目标库
COUNT(*)返回非零但SELECT * FROM t1 LIMIT 1报ERROR 2013:说明 SQL 文件截断,myloader执行了一半就崩了,但表已建好且有部分数据 - 目标库该表
COUNT(*)为 0:说明myloader还没开始导入这张表,下次加--resume会正常执行 - 目标库该表存在但行数远少于源库,且
myloader日志里有Skipping table t1 (non-empty):这是最危险的情况,--resume误判了,必须删表重导
文件损坏时 --resume 会跳过残缺数据
myloader --resume 对损坏毫无感知。如果源备份目录里 db1/t1.sql 因磁盘坏道导出不全(比如最后一条 INSERT 缺少右括号或逗号),myloader 仍会因“表非空”跳过它,导致目标数据永远残缺。
验证文件是否损坏,三步走:
- 用
file db1/t1.sql确认是ASCII text,不是data或empty - 用
head -n 50 db1/t1.sql | tail -n 10看结尾是否为完整INSERT语句(末尾有分号、括号闭合) - 用
grep -c '^INSERT' db1/t1.sql和源库该表实际 INSERT 数量比对(需提前记录)
发现损坏后,不要重跑 myloader。小表直接删目标表、去掉 --resume 单独重导;大表若源 .ibd 已毁,只能上 Percona Data Recovery Tool for InnoDB 解析原文件导 CSV,再手工导入——但必须配 pt-table-checksum 全库校验,不能只信行数。
离线环境更要防终端断连
离线迁移常跑在跳板机或本地终端上,ssh 默认超时(ServerAliveInterval=0)会让长任务无声中断。这不是网络问题,是连接保活没设。
正确做法:
- 导出/导入前,先用
ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3 user@host连入 - 进机器第一件事:启
tmux或screen,再跑mydumper或myloader - 万一断线,重连后
tmux attach就能看到实时日志,进程其实没死
别用 mosh——它不支持端口转发,离线内网环境根本连不上 DB;也别信 nohup,它不解决 SSH 层主动断连,日志还容易被轮转冲掉。
真正卡点永远不在“怎么续”,而在“续之前敢不敢删表重来”。每次重试前,必须确认那张表在目标库是空的、SQL 文件是完整的、行数对得上——否则 --resume 就是埋雷。


















