调大slave_parallel_workers不能解决延迟,必须先设slave_parallel_type='LOGICAL_CLOCK'并确保主库启用组提交;否则即使workers设为32也仅单线程回放。

调大 slave_parallel_workers 本身不能解决延迟——它只是并行复制的“油门”,但没配对的“引擎”和“变速箱”,踩再狠也跑不快。
为什么设了 slave_parallel_workers 却还是单线程回放
最常见原因是 slave_parallel_type 还是默认的 DATABASE。这个模式下,只有跨不同库(schema)的事务才能分发给不同 worker;如果主库所有写都在一个库(比如全在 app_db),那不管 slave_parallel_workers 设成 8 还是 32,从库 SQL 线程永远只用 1 个 worker 回放。
- 必须先执行:
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK'; - 确认生效:
SELECT @@slave_parallel_type;返回LOGICAL_CLOCK -
slave_parallel_workers在DATABASE模式下大于 0 是无效配置,不会报错,但也不会起作用
slave_parallel_workers 设多少才真正有用
不是越多越好,超过实际可并行事务数后,协调线程(Coordinator)分发开销、线程上下文切换、锁争用反而拖慢整体吞吐。实测中,4~8 是多数 OLTP 场景的合理起点。
- 建议从
4开始:SET GLOBAL slave_parallel_workers = 4; - 观察
SHOW PROCESSLIST中是否有多个system user开头的 Worker 线程处于Executing event或Waiting for an event from Coordinator - 若 CPU 负载不均(仅少数线程跑满,其余闲置),说明瓶颈不在并行度,而在磁盘 I/O 或 SQL 回放本身(比如大
UPDATE缺索引) - 物理 CPU 核数为 8 的机器,设成
16通常收益甚微,还可能因调度抖动导致Seconds_Behind_Master波动更大
开了并行但 Seconds_Behind_Master 还是不准
这个值只反映 SQL 线程读取 relay log 的位置与系统时间差,不统计 worker 队列积压。尤其在 LOGICAL_CLOCK 模式下,SQL 线程只是分发器,真实执行由 worker 完成——它完全不感知。
- 更可靠的判断方式:
SELECT MASTER_POS_WAIT('<code>mysql-bin.000001', 123456789, 0);(用SHOW MASTER STATUS当前位点)返回0才代表完全追平 - 查 worker 实际进度:
SELECT * FROM performance_schema.replication_applier_status_by_worker\G,看LAST_SEEN_TRANSACTION和APPLYING_TRANSACTION - 监控
Relay_Log_Space(持续增长说明 IO 线程或网络慢)、Read_Master_Log_Pos与Exec_Master_Log_Pos差值(字节级延迟)
主库没配组提交,并行就是摆设
LOGICAL_CLOCK 依赖主库 binlog 中的 last_committed 和 sequence_number 标记,而这由主库组提交机制生成。如果主库 binlog_group_commit_sync_delay = 0(默认),高并发小事务容易各自成组,从库 worker 收到的几乎全是单事务组,自然无法并行。
- 主库上可尝试:
SET GLOBAL binlog_group_commit_sync_delay = 100000;(单位微秒,即 100ms) - 配合:
SET GLOBAL binlog_group_commit_sync_no_delay_count = 20;(凑够 20 个事务就强制提交,防卡死) - 注意:这会轻微增加主库响应延迟,需权衡业务对写入 RT 的敏感度
- 验证是否生效:主库执行
SHOW MASTER STATUS,观察Executed_Gtid_Set是否连续;跳跃严重说明组提交未起效
真正卡住并行复制的,往往不是参数没开,而是主库写法(单表热点更新、大事务、无唯一索引的 UPDATE)、binlog 格式(非 ROW)、或事务依赖检测(WRITESET 退化)这些隐性条件。调 slave_parallel_workers 前,先确认 binlog_format = ROW、slave_preserve_commit_order = ON、且主库确实产生了多事务组——否则只是在调一个不工作的开关。


















