MySQL并行复制不生效主因是事务未被识别为可并行,需主库启用组提交(binlog_order_commits=OFF+sync_binlog=1)、从库设slave_parallel_type=LOGICAL_CLOCK,并合理设置slave_parallel_workers(建议4~min(8,CPU核心数×2))。

为什么开了slave_parallel_workers却没提速
并行复制不生效,大概率是事务没被识别为可并行——MySQL的MTS(Multi-Threaded Slave)只对基于binlog_group_commit机制形成的“组提交”事务启用并行。如果主库没开启组提交(即binlog_order_commits=OFF未配合sync_binlog=1等),或者写入压力低、事务太零散,从库看到的就全是单事务组,slave_parallel_workers再多也闲置。
实操建议:
- 主库确认
binlog_format=ROW且binlog_order_commits=OFF(这是组提交前提) - 主库设置
sync_binlog=1+innodb_flush_log_at_trx_commit=1,保证日志落盘节奏与组提交对齐 - 从库开启
slave_parallel_type=LOGICAL_CLOCK(别用DATABASE,已过时且效果差) - 检查
SHOW SLAVE STATUS\G中Seconds_Behind_Master下降趋势,同时看Slave_SQL_Running_State是否频繁出现Waiting for preceding transaction to commit——这说明组依赖链过长,不是并行瓶颈,而是事务逻辑串行化太重
slave_parallel_workers设多少才合理
不是越多越好。线程数超过CPU核心数后,上下文切换开销会抵消并行收益;若主库平均每秒产生不到5个事务组,设16个worker纯属浪费资源。
实操建议:
- 先观察主库
SHOW GLOBAL STATUS LIKE 'Binlog_group_commit%,看Binlog_group_commit_trigger_count和Binlog_group_commit_trigger_timeout实际触发频率 - 从库初始设
slave_parallel_workers=4,压测时用pt-heartbeat对比延迟变化,再逐步调到min(8, CPU核心数×2) - 避免设为0或1——那是退化回单线程模式;也别跨过16,MySQL 8.0对高worker数的调度优化有限
- 记得动态生效:
STOP SLAVE; SET GLOBAL slave_parallel_workers = 8; START SLAVE;
为什么LOGICAL_CLOCK模式下仍卡在某个事务
MySQL用last_committed和sequence_number标记事务依赖关系。last_committed相同的事务可并行,但只要有一个事务last_committed值极大(比如大事务刷了上万行),它之后所有事务都会被阻塞等待——因为它们的last_committed都等于这个大事务的sequence_number。
实操建议:
- 主库避免超大事务:单事务更新/插入超过10万行时,拆成
COMMIT间隔≤5000行的批次 - 从库监控
SHOW PROCESSLIST里长时间Waiting for dependent transaction to commit的状态,定位源头大事务 - 别指望
slave_preserve_commit_order=ON能缓解——它反而强化依赖,仅在需要严格一致性时打开 - 用
SELECT * FROM performance_schema.replication_applier_status_by_coordinator;查各worker负载是否严重不均
GTID环境下并行复制要注意什么
GTID本身不改变MTS行为,但gtid_mode=ON后,slave_parallel_type=LOGICAL_CLOCK仍是唯一推荐选项;若误配slave_parallel_type=DATABASE,GTID复制会直接报错ERROR 1786 (HY000): Statement violates GTID consistency。
实操建议:
- GTID开启后,
slave_parallel_workers必须≥1,否则启动失败 - 跳过事务时不用
SET GLOBAL sql_slave_skip_counter(不支持GTID),改用GTID_SUBTRACT或mysqlbinlog --exclude-gtids生成跳过语句 - 主从GTID不一致时,
START SLAVE可能卡在Retrieving GTID set for channel ''——先确认SELECT @@global.gtid_executed在主从是否对得上
真正难调的从来不是参数数字,而是主库事务粒度和从库worker调度器之间的隐式耦合。一个last_committed飙升的慢查询,比十个slave_parallel_workers更致命。










