mysqldump默认锁表主因是ftwrl全局锁,解决核心是“不锁”或“极短锁”:innodb库应严格使用--single-transaction+--skip-lock-tables组合,禁用--lock-tables,确保全库为innodb引擎,并搭配--quick流式导出。

mysqldump 默认会锁表,尤其在 MyISAM 表或未加合适参数的 InnoDB 表上,直接导致业务写入卡住。真正能压到分钟级停写窗口的方案,不是“怎么导得快”,而是“怎么不锁”或“锁得极短”。
用 --single-transaction + --skip-lock-tables 绕过 InnoDB 锁表
这是最常用也最容易翻车的组合。它只对 InnoDB 有效,本质是靠事务快照实现一致性读,不触发 FLUSH TABLES WITH READ LOCK。但前提是:
-
innodb_lock_wait_timeout要设够长(建议 ≥600),否则大表导出中途可能被 kill - 不能和
--lock-tables共存,否则快照失效,退化为全局只读锁 - 如果库中混有 MyISAM 表,整个 dump 过程仍会被
--lock-all-tables拦住——必须提前确认存储引擎分布 - 导出时若发生长事务未提交,
SELECT可能被阻塞,表现为 dump 进程卡在某个表不动
大表必须分片导出,别碰全库 mysqldump --all-databases
单次全库 dump 在千万级表上极易引发主从延迟飙升、连接堆积甚至 OOM。实际操作中应按表或主键范围切分:
- 对有自增主键的表,用
--where="id BETWEEN 1 AND 1000000"分批导出,每批控制在 50 万行内 - 配合
--quick强制流式读取,避免 MySQL 把整张表加载进内存 - 导出时不加
--extended-insert会导致每行一个INSERT,导入时解析开销剧增;正式迁移必须开启它 - 跳过非核心对象:
--skip-triggers、--skip-routines、--no-create-info(结构已单独导)可显著减小文件体积和解析压力
真正零锁表:用 pt-online-schema-change 做在线迁移
当业务完全不能接受任何只读锁,或者你没权限改 innodb_lock_wait_timeout 等全局变量时,pt-online-schema-change 是更稳妥的选择。它不依赖“先空表后灌数据”,而是在原表旁建影子表、用触发器同步增量、分 chunk 拷贝并在线建索引:
- 必须确保原表有主键或唯一非空索引,否则无法分片
- 建索引过程是后台异步的,不会阻塞主表 DML,但会持续占用磁盘 I/O 和 CPU
- 触发器会带来轻微写入延迟(通常
- 迁移期间若发生主从延迟,工具会自动暂停拷贝,但需监控
Seconds_Behind_Master是否持续为 0
DNS 切流前必须验证主从真正就绪,不是“看起来没延迟”
很多人以为 Seconds_Behind_Master = 0 就能切,结果立刻出现脏读或双写。真实判断依据是:
- 执行
SHOW SLAVE STATUS\G,确认Read_Master_Log_Pos和Exec_Master_Log_Pos完全相等,且持续稳定至少 30 秒 - DNS TTL 必须 ≤ 30s,否则客户端缓存旧 IP,部分请求仍打到旧库
- 禁用中间件读负载均衡,切流期间所有读强制走新主库,避免跨库不一致
- 应用层连接池(如 HikariCP)里的“僵尸连接”必须清理——它们仍连着旧地址,直到 idleTimeout 触发重连











