slave_parallel_workers设为大于0仅是开启多线程复制的开关,实际并行效果取决于主库binlog_format=ROW、binlog_transaction_dependency_tracking=WRITESET、表有主键或唯一键,以及从库slave_preserve_commit_order配置是否合理。

slave_parallel_workers 设为大于 0 的值,只是开启多线程复制的“开关”,不是“加速器”。真正决定它能不能跑起来、能跑多快的,是主库的 binlog_transaction_dependency_tracking 模式、表结构、以及从库是否被强制保序。
slave_parallel_workers 为什么设了却没效果?
常见现象:
-
SHOW SLAVE STATUS\G中Slave_SQL_Running_State长期卡在Waiting for preceding transaction to commit -
performance_schema.replication_applier_status_by_worker里多数 worker 线程状态是Waiting for an event from Coordinator,WORKERS_PROCESSED几乎不增长
根本原因不是参数没生效,而是 MySQL 主动降级回单线程——因为事务之间存在逻辑依赖。
关键判断点:
- 主库 binlog 格式不是
ROW→ 直接退化为单线程(STATEMENT或MIXED不支持 writeset) - 主库未启用
binlog_transaction_dependency_tracking = WRITESET→ 默认用COMMIT_ORDER,只看提交时间,对同一 session 连续事务完全无法并行 - 表无主键或唯一键 →
WRITESET无法生成写集,自动 fallback 到COMMIT_ORDER,甚至进一步退化 - 从库启用了
slave_preserve_commit_order = ON(8.0.27+ 默认开启)→ 即使事务可并行,也强制按主库顺序提交,worker 实际串行等待
验证方式:
- 查主库:
SELECT @@binlog_transaction_dependency_tracking, @@binlog_format, @@transaction_write_set_extraction; - 查从库:
SELECT * FROM performance_schema.replication_applier_status_by_coordinator\G,重点看WORKERS_WAITING是否远高于WORKERS_PROCESSED
怎么让 slave_parallel_workers 真正跑起来
必须同时满足三端配置,缺一不可:
-
主库侧(最容易被忽略):
-
SET PERSIST binlog_transaction_dependency_tracking = 'WRITESET'; -
SET PERSIST transaction_write_set_extraction = 'XXHASH64'; -
SET PERSIST binlog_row_image = 'FULL';(MINIMAL会导致写集提取失败) - 确保所有被写入的表都有
PRIMARY KEY或非空UNIQUE KEY
-
-
从库侧(运行时可调):
-
STOP SLAVE; -
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';(8.0 默认已是,但需确认) -
SET GLOBAL slave_parallel_workers = 8;(建议值:CPU 核心数 × 1.5,不超过 16) - 如业务允许乱序提交,可临时关掉保序:
SET GLOBAL slave_preserve_commit_order = OFF;
-
-
重启复制:
-
START SLAVE; - 等 30 秒后查
performance_schema.replication_applier_status_by_worker,确认多个 worker 的LAST_APPLIED_TRANSACTION在持续推进
-
slave_parallel_workers 设多大才合适?
不是越大越好,线程数过高反而拖慢整体速度:
- 超过物理 CPU 核心数太多 → 上下文切换开销陡增,
SHOW PROCESSLIST可见大量Slave_worker处于sleep或锁等待 - 建议起始值:
- 4 核机器 → 设为 6
- 8 核机器 → 设为 12
- 16 核以上 → 一般不超过 16,优先优化主库 writeset 和表结构
- 如果观察到
slave_pending_jobs_size_max频繁打满(默认 128MB),可适当调大:-
SET GLOBAL slave_pending_jobs_size_max = 268435456;(256MB)
-
容易被忽略的硬性前提
slave_parallel_workers 能否起效,最终取决于最薄弱的一环:
- DDL 语句(如
ALTER TABLE、DROP INDEX)始终串行执行,且会阻塞后续所有事务回放 -
INSERT ... SELECT、CREATE TABLE ... AS SELECT这类语句在 binlog 中标记为不可并行,即使有主键也会被跳过 writeset 计算 - 主库如果用了
MyISAM表(哪怕只有一张),整个复制链路会降级,writeset 失效 - GTID 必须开启(
gtid_mode = ON),否则部分 writeset 元数据无法正确传递
真正卡住性能的,往往不是线程数不够,而是某张没主键的表、一次 DDL、或者主库还开着 STATEMENT 格式。先查 replication_applier_status_by_coordinator,再盯住那张“拖后腿”的表,比盲目加线程有用得多。


















