mysqldump卡住主库本质是锁资源争抢,因--lock-tables触发flush tables with read lock等待全局读锁,而长事务持有mdl写锁导致阻塞;改用--single-transaction可避免锁表,但需全为innodb表且注意快照延迟。

主库压力大导致 mysqldump 阻塞,本质是 dump 线程和主库写入线程争抢 IO 与锁资源,不是调个参数就能绕开的。
为什么 mysqldump 会卡住主库?
在 MySQL 5.7 中,mysqldump 默认使用 --lock-tables(除非显式加 --skip-lock-tables),它会执行 FLUSH TABLES WITH READ LOCK。这个操作要等所有活跃写事务提交、释放 MDL 写锁后才能拿到全局读锁——如果主库正跑着一个长事务、或大量小事务堆积未提交,dump 就会卡在 Waiting for global read lock 状态,同时阻塞后续所有 DML。
- 现象:执行
mysqldump后,SHOW PROCESSLIST里看到状态为Waiting for global read lock,且主库写入明显变慢甚至停滞 - 根本原因:不是 dump 本身慢,而是它在“等锁”,而锁被其他线程长期持有
- 5.7 的限制:不支持
LOCK INSTANCE FOR BACKUP(8.0.1 才引入),无法绕过 MDL 锁做一致性备份
用 --single-transaction 替代 --lock-tables
对 InnoDB 表,--single-transaction 是更安全、低侵入的选择。它利用 MVCC 在事务快照中导出数据,全程不加全局读锁,也不会阻塞主库写入。
- 必须确保所有表都是 InnoDB,否则会自动退化为
--lock-tables - 需配合
--no-tablespaces(避免导出 .ibd 文件引发额外 IO) - 实际命令示例:
mysqldump -u root -p --single-transaction --no-tablespaces mydb > backup.sql - 注意:如果主库存在长运行的
REPEATABLE READ事务,dump 仍可能因 snapshot 被拖慢,但不会阻塞新事务
降低 dump 对磁盘 IO 的冲击
即使不锁表,mysqldump 全表扫描 + 大量 SELECT 也会打满磁盘带宽,尤其当 innodb_buffer_pool_size 不足以缓存热点数据时,IO 压力直接传导到主库。
- 避开业务高峰执行,例如凌晨低峰期
- 限制 dump 进程 IO 优先级(Linux 下用
ionice -c2 -n7):ionice -c2 -n7 mysqldump ... - 分库分表导出,避免单次 dump 超过 10GB;对大表用
--where分批次(如按时间字段切片) - 禁用压缩(
gzip)在 dump 过程中做,改用管道后压:mysqldump ... | gzip > backup.sql.gz,避免 CPU 和 IO 双重挤压
真正缓解主库压力,得从源头减负
靠 dump 参数优化只是止痛,主库高压力往往来自设计或使用方式问题。Dump 卡住只是表象,背后可能是:
- 缺少主键/唯一索引的大表被频繁更新 → ROW 格式 binlog 体积爆炸,加重 dump 时的全表扫描负担
- 未拆分的批量 INSERT 或 UPDATE → 产生大事务,让
--single-transaction快照拉得太长,甚至触发max_allowed_packet截断 - binlog_format = ROW 但没配
binlog_row_image=MINIMAL→ 记录冗余字段,增大 IO 和网络传输量 - 监控盲区:只看
Seconds_Behind_Master,却忽略主库Threads_running和Innodb_data_reads指标飙升
最常被忽略的一点:不要在主库上做报表类查询或 dump,这类只读负载应全部路由到从库。哪怕从库延迟几秒,也比把主库拖垮强得多。











