seconds_behind_master不准是因为它仅基于binlog事件时间戳估算延迟,不反映大事务阻塞、锁等待、时钟不同步或io线程滞后等真实情况;真正应关注slave_io_running、slave_sql_running状态及relay_log_space增长,并用pt-heartbeat实测延迟。

怎么看Seconds_Behind_Master不准了
Seconds_Behind_Master 显示为 0 或很小,但业务查不到刚写入的数据——这很常见,不代表真没延迟。它只对比当前执行事务的 binlog 时间戳和系统时间,一旦 SQL 线程卡在锁、DDL、大事务回放中,这个值就“冻住”了,实际已落后几分钟甚至更久。
真正要盯的是:SHOW SLAVE STATUS\G 里的这三项:
-
Slave_IO_Running: Yes—— IO 线程是否还在拉日志(No表示断连或权限问题) -
Slave_SQL_Running: Yes—— SQL 线程是否在执行(No才是真卡点) -
Relay_Log_Space持续上涨 —— 中继日志堆积,说明 SQL 线程追不上
更准的判断方式是用 pt-heartbeat:它在主库定时写心跳记录,从库读取并计算差值,结果反映真实延迟,不受事务阻塞干扰。
并行复制启动后报错 Slave_SQL_Running: No
启用 slave_parallel_type=LOGICAL_CLOCK 或 WRITESET 后,SQL 线程突然停止,SHOW SLAVE STATUS 的 Seconds_Behind_Master 变成 NULL,错误日志里常出现:
Could not execute Write_rows event on table xxx; Error_code: 1032; Handler error HA_ERR_END_OF_FILE
这类报错本质是并行回放破坏了事务间依赖顺序,尤其在以下场景高发:
- 主库用了
binlog_format=STATEMENT—— 必须切到ROW,否则并行无法识别行级变更粒度 - 表没主键或唯一键 ——
WRITESET依赖主键哈希分组,无主键时退化为单线程,还可能因找不到匹配行报错 1032 - 跨库事务混写(比如事务里同时更新
db1.t1和db2.t2)——slave_parallel_type=DATABASE模式下直接不支持,并行线程会争抢资源出错 - 从库开了
read_only=1但有其他连接绕过执行了 DML —— 并行回放时检测到数据不一致,直接中断
修复前先确认:SELECT @@binlog_format; 和 SHOW CREATE TABLE xxx; 查主键是否存在。
为什么开了 slave_parallel_workers 却没提速
设了 slave_parallel_workers=16,但 SHOW PROCESSLIST 里只看到 1 个 SQL thread 在干活,其余线程空闲——这不是配置没生效,而是并行策略根本没触发。
关键看三个条件是否同时满足:
-
slave_parallel_type必须是LOGICAL_CLOCK(5.7+)或WRITESET(8.0.19+),DATABASE类型只对多库写有效,单库写仍是单线程 - 主库必须开启
binlog_transaction_dependency_tracking=WRITESET(8.0)或至少COMMIT_ORDER(5.7),否则从库收不到并行提示信息 - 事务本身得“可并行”:同一事务内不能有跨表强依赖(如先删父再插子),也不能含 DDL(
ALTER会强制串行化)
验证是否真并行:执行 SHOW PROCESSLIST;,正常应看到多个 Worker 线程(如 Worker 1, Worker 2),且状态为 executing;若全是 waiting for an event from Coordinator,说明没活干,得回头检查主库事务结构。
大事务一来,并行复制就崩
业务批量导入、日志清理这类操作,一个事务改几十万行,哪怕开了 WRITESET,从库照样卡死:因为整个事务被当作一个原子单位,无法拆解,并行线程只能排队等它执行完。
这不是并行复制的 bug,是设计使然——事务一致性优先于速度。所以排查时别只盯着复制参数,得顺藤摸瓜找源头:
- 查主库慢日志:
mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log,重点看Rows_examined和Rows_affected超大的事务 - 监控
information_schema.INNODB_TRX表,实时抓长事务:SELECT trx_id, trx_started, trx_rows_modified FROM information_schema.INNODB_TRX WHERE trx_rows_modified > 10000; - 业务侧必须改写逻辑:用
LIMIT分批提交,比如DELETE FROM logs WHERE ts ,每批显式 <code>COMMIT
最容易被忽略的一点:即使从库硬件再强、并行线程再多,只要主库还在发巨型事务,从库永远追不上。优化必须打穿到业务层,不能只调数据库参数。











