分库分表下mysql备份需解决跨库一致性问题:单库mysqldump无法保证原子性;flush tables with read lock+show master status可实现物理级一致备份;gtid+从库stop slave为无锁方案;xa事务须备份前清理prepared状态。

分库分表本身不改变 MySQL 备份的本质逻辑,但会显著放大一致性风险——你无法靠单条 mysqldump 命令保证跨库事务的原子性,也不能默认所有分表在备份瞬间状态同步。
分库分表场景下 mysqldump 的一致性陷阱
多数人直接对每个库单独执行 mysqldump -B db1、mysqldump -B db2,看似合理,实则埋雷:
- 不同库备份起始时间不同,若存在跨库业务(如订单库写入后触发用户库积分更新),备份文件之间可能呈现“中间态”,还原后数据逻辑错乱;
-
mysqldump默认不加全局读锁(--single-transaction仅对 InnoDB 有效,且只保障单库内一致性); - 若某库含 MyISAM 表,
--single-transaction完全失效,该库备份期间写入将直接导致数据不一致。
物理级一致性:用 FLUSH TABLES WITH READ LOCK + SHOW MASTER STATUS
这是最稳妥的跨库逻辑备份方案,适用于主从架构且能短暂停写(秒级)的场景:
- 先在主库执行
FLUSH TABLES WITH READ LOCK,阻塞所有写操作并刷新脏页; - 立刻执行
SHOW MASTER STATUS,记录File和Position(用于后续恢复到精确位点); - 在锁持有状态下,并行调用多个
mysqldump -B备份各分库,确保所有 dump 起始时间戳一致; - 备份完成后,立即执行
UNLOCK TABLES,释放锁。
注意:FLUSH TABLES WITH READ LOCK 会阻塞 DDL,且在高并发写入时可能引发堆积,务必避开业务高峰。
无锁方案:依赖 GTID + --set-gtid-purged=OFF 配合从库备份
若系统已开启 GTID 且有从库,可规避主库加锁:
- 在从库上执行
STOP SLAVE,暂停复制; - 确认
Seconds_Behind_Master = 0后,执行mysqldump --single-transaction --set-gtid-purged=OFF -B db1 db2 ...; - 备份完成后,执行
START SLAVE恢复复制; - 导出的 SQL 文件不含 GTID 信息,导入时需手动指定
SET GLOBAL gtid_purged = '...'(根据备份时刻从库的gtid_executed确定)。
关键点:--set-gtid-purged=OFF 不是省略 GTID,而是把 GTID 控制权交还给目标实例,避免因 GTID 冲突导致导入失败。
分布式事务表(XA)与分库备份的不可兼得性
如果你的应用层用了 XA 分布式事务协调多库提交,必须清醒认识到:逻辑备份天然无法还原 XA 事务的 prepare 状态。
-
mysqldump不保存 XA 事务日志,备份文件里只有最终 commit/rollback 后的数据快照; - 若备份时刻恰好有 XA 事务处于
PREPARED状态,该事务不会被 dump 出来,还原后这部分数据永久丢失; - 真正安全的做法是:备份前强制
XA RECOVER+XA COMMIT/XA ROLLBACK清理所有悬挂事务,再执行备份。
这说明,分库分表环境下的备份不是纯运维动作,必须和应用事务生命周期对齐——最容易被忽略的,恰恰是那几行清理 XA 的 SQL。











