答案是mysqldump默认使用FLUSH TABLES WITH READ LOCK全局锁,阻塞从库SQL线程回放binlog,导致Seconds_Behind_Master飙升,读写分离中间件据此拒绝读请求引发大面积超时。

凌晨时段连接 MySQL 大面积超时,八成不是网络或负载问题,而是定时任务(尤其是备份)触发了 mysqldump 全局锁,间接导致主从延迟飙升、从库 SQL 线程卡死、应用连从库时因 Seconds_Behind_Master 过大被路由中间件/读写分离组件主动拒绝——这种“超时”本质是服务端拒绝连接,而非 TCP 层断开。
为什么 mysqldump 在凌晨会引发连接超时
mysqldump 默认加 FLUSH TABLES WITH READ LOCK(FTWRL),这个锁会阻塞所有写操作,但更关键的是:它会卡住从库的 SQL 线程回放 binlog。一旦 SQL 线程停摆,Seconds_Behind_Master 就开始疯涨。很多读写分离中间件(如 MyCat、ShardingSphere)或应用层路由逻辑会设置阈值(比如 > 60 秒),自动将读请求切到主库或直接返回错误。
- 现象不是“连不上”,而是
Communications link failure或Connection refused,但telnet能通、show processlist里能看到大量Sleep连接 - 查
SHOW SLAVE STATUS\G,Seconds_Behind_Master持续 > 300,且SQL_Thread_State是Waiting for master to send event或空(说明卡在锁上) - 备份脚本若用了
--single-transaction,只对 InnoDB 有效;如果从库混用 MyISAM 表,照样得 FTWRL - 凌晨跑报表查询 + 备份同时发生?FTWRL 第一步
Close tables会等那个长查询结束,期间所有新写入都排队——从库积压雪球越滚越大
如何确认是定时任务引发的连锁反应
别只盯着应用日志,先看时间线和数据库状态是否对齐:
- 查备份脚本执行时间:
grep 'mysqldump' /var/log/cron*或systemctl list-timers --all | grep backup - 查 MySQL 错误日志中对应时段是否有
Aborted connection+ “due to timeout” 或 “waiting for table flush” - 对比故障时间点与
SHOW PROCESSLIST中Command = 'Query'且State = 'Locked'或'Waiting for table flush'的进程数量 - 检查从库是否启用了半同步:
SELECT @@rpl_semi_sync_slave_enabled;如果是,主库事务提交会被拖慢,加剧应用侧感知到的“超时”
怎么避免备份影响线上连接
核心思路是:不让备份锁表,或者让锁的影响范围可控。
- 从库备份必须加
--skip-lock-tables(仅适用于--single-transaction且全为 InnoDB);否则换用mysqlpump或mydumper,它们默认不依赖 FTWRL - 禁止在从库执行
mysqldump时使用--master-data(它强制 FTWRL),改用--dump-slave=2并配合START SLAVE UNTIL暂停复制后再 dump - 把备份窗口错开高负载时段,比如避开凌晨 2:00–4:00(报表跑完+缓存失效高峰期)
- 给从库单独配一个低优先级的复制线程(MySQL 8.0.23+ 支持
SET PERSIST replication_threads_priority = -10),降低备份期间对 SQL 回放的抢占
应用侧临时兜底怎么做
等 DBA 改备份策略期间,应用不能干等。重点不是延长超时,而是绕过已不可用的从库:
- Spring Boot + ShardingSphere 场景下,在
application.yml中配置props.sql-show: true和sql-comment-parse-enable: true,然后在 SQL 里加注释/*+ readwrite() */ SELECT ...强制走主库 - HikariCP 连接池启用
connection-init-sql=SELECT 1,并设connection-timeout=3000(3 秒),比默认 30 秒快得多,快速失败后走降级逻辑 - 监控
Seconds_Behind_Master指标(通过SHOW SLAVE STATUS定时采集),一旦 > 60 秒,自动触发读请求降级开关(比如 Redis 里设个slave_unhealthy:1) - 注意:不要依赖
autoReconnect=true,MySQL 8.0 已彻底移除该参数,且它无法解决锁表导致的连接挂起
真正麻烦的不是备份本身,而是备份、从库延迟、读写分离路由、应用重试机制这四层叠加后的“雪崩式误判”。每层都看似合理,合起来就变成凌晨三点的生产事故。排查时一定按时间戳串起 cron 日志、MySQL error log、应用 access log 和中间件 metrics,漏掉任意一层,结论都可能偏移。


















