根本原因是mysqldump默认触发FTWRL全局锁,而非备份速度慢;--single-transaction仅对InnoDB生效,混用MyISAM表、冲突参数或长事务均会导致降级锁表,须配合--net-write-timeout等调优及权限校验。

mysqldump 备份大表时引发业务超时,根本不是“备份慢”,而是它默认触发了 FLUSH TABLES WITH READ LOCK(FTWRL)全局锁,直接卡死所有写操作——哪怕你只导一个 20GB 的 order_detail 表,只要没加对参数,整个库的 INSERT/UPDATE/DELETE 就会排队等锁,应用自然大面积报 Communications link failure 或 Connection refused。
为什么加了 --single-transaction 还会锁表?
这个参数只对 InnoDB 表生效,且有严格前提:
- 库中不能混用
MyISAM表——哪怕只有一个mysql.general_log是 MyISAM,mysqldump就会自动降级为 FTWRL - 不能同时指定
--lock-all-tables、--master-data等强制锁表参数(它们和--single-transaction冲突) - 备份期间若存在长事务未提交,
mysqldump会等它结束才启动快照,这期间 FTWRL 已在排队阻塞新写入 - 从库上执行时,如果
Seconds_Behind_Master > 0,SQL 线程可能正卡在某个 DDL 上,导致 FTWRL 第一步Close tables无限等待
net_read_timeout 和 net_write_timeout 不调大会直接断连
大表导出时,MySQL Server 往 mysqldump 进程发数据,如果客户端处理慢(比如写到 NFS 或压缩慢),Server 端就会卡在 Writing to net 状态。一旦超过 net_write_timeout(默认 60 秒),连接被主动断开,报错 Error 2013: Lost connection during query。
必须显式传参覆盖,默认值完全不够用:
mysqldump --net-read-timeout=300 --net-write-timeout=300 -u user -p db_name table_name > backup.sql
注意:--net-read-timeout 是服务端等客户端发下一条请求的时间,--net-write-timeout 是服务端往客户端写数据的单次上限;两个值建议设成一样,且不低于 300。
备份脚本里藏着的隐形杀手:pt-kill 和权限误配
很多团队启用了 pt-kill 自动杀长查询,但忘了给备份进程白名单。结果 mysqldump 扫描大表时被当成“慢查询”干掉,日志里只看到连接中断,实际是被 pt-kill 主动 kill。
检查方式很简单:
-
ps aux | grep pt-kill看是否运行中 -
pt-kill --print --busy-time 10 --match-command Query --ignore-user dump加--ignore-user或--match-program mysqldump排除备份进程 - 权限不足也会表现类似超时:
LOCK TABLES权限缺失时,mysqldump会反复重试锁表直到超时,看起来像卡死——用SHOW GRANTS FOR 'backup_user'@'%';确认是否含SELECT, LOCK TABLES, RELOAD, SHOW VIEW, TRIGGER
真正卡住的从来不是磁盘或网络,而是锁等待链:一个未提交事务 → 阻塞 FTWRL → 卡住 SQL 线程 → 主从延迟飙升 → 读写分离中间件拒接读请求 → 应用报超时。排查时别一上来就查 CPU 或 IO,先看 SHOW PROCESSLIST 里有没有大量 State = 'Waiting for table flush',再查 Seconds_Behind_Master 是否同步飙升——这两条对上了,基本就是备份锁惹的祸。


















