并行复制未生效是因为未满足硬性前提:slave_parallel_type必须为logical_clock、主库binlog_format=row且binlog_transaction_dependency_tracking=writeset、从库slave_preserve_commit_order=off,缺一即退化为单线程。

设了 slave_parallel_workers 却还是单线程回放,说明并行复制根本没生效,不是配置“开了就行”,而是有一连串硬性前提卡在中间。
为什么 SHOW PROCESSLIST 里只看到一个 SQL 线程?
这是最直观的信号:从库实际仍在用传统单线程模式回放 relay log。常见原因不是参数没设,而是被自动降级:
-
slave_parallel_type是DATABASE(尤其在旧配置迁移后残留),它只对跨库事务并行,单库写入直接退化为单线程 - 主库
binlog_format不是ROW——STATEMENT或MIXED下WRITESET无法提取写集 - 从库
slave_preserve_commit_order = ON(MySQL 8.0 默认开启),它会强制 worker 等待前一个事务提交完成,导致并发度归零 - relay log 里存在 DDL(如
ALTER TABLE)或无主键表的 DML,这类事件被标记为不可并行,后续所有事务排队等待
SHOW SLAVE STATUS\G 中哪些字段暴露单线程真相?
别只盯 Seconds_Behind_Master,这几个字段才是关键证据:
-
Slave_SQL_Running_State显示Reading event from the relay log:协调器(coordinator)线程在读日志,但没分发给 worker,说明并行调度链路断了 -
Relay_Log_Space持续上涨,而Exec_Master_Log_Pos几乎不动:SQL 线程堵死,中继日志堆积,典型单线程瓶颈 -
Retrieved_Gtid_Set和Executed_Gtid_Set差距大,但Seconds_Behind_Master不涨:事务已拉取,却因依赖检测失败或写集为空,被 coordinator 强制串行化
MySQL 8.0 启用 WRITESET 并行必须配齐的主从参数
WRITESET 不是“开个开关”就提速,它是一套协同机制,漏掉任意一环都会 fallback 到单线程:
- 主库必须设:
binlog_transaction_dependency_tracking = WRITESET(不能是COMMIT_ORDER) - 主库必须设:
transaction_write_set_extraction = XXHASH64 - 主库必须设:
binlog_row_image = FULL(否则写集提取不全,空写集 → 串行) - 从库必须设:
slave_parallel_type = LOGICAL_CLOCK(8.0 默认,但检查确认) - 从库必须设:
slave_parallel_workers > 0(建议值 = CPU 核数 × 1.5,如 12 核设 18,超 32 反而负优化) - 从库可选关:
slave_preserve_commit_order = OFF(若不需要严格保序,这是提升并发度最直接的开关)
改完必须执行:STOP SLAVE; START SLAVE;,仅 SET GLOBAL 不触发 coordinator 重建。
验证并行是否真在跑:别信状态,看 performance_schema
SHOW SLAVE STATUS 只告诉你“想不想并行”,performance_schema 才告诉你“到底并没并行”:
- 查协调器负载:
SELECT * FROM performance_schema.replication_applier_status_by_coordinator\G,看WORKERS_PROCESSED是否持续增长;若长期为 0,说明 coordinator 没分发任务 - 查 worker 实际运行:
SELECT * FROM performance_schema.replication_applier_status_by_worker\G,看LAST_APPLIED_TRANSACTION和APPLYING_TRANSACTION是否在滚动更新;若多个 worker 的LAST_APPLIED_TRANSACTION长期相同,说明它们在等同一个锁或事务 - 最关键的线索:
SELECT * FROM performance_schema.replication_applier_status_by_worker WHERE LAST_ERROR_NUMBER != 0\G,常能挖出被静默降级的事务(如写集为空、DDL 阻塞)
最容易被忽略的是表结构:哪怕所有参数全对,只要某张表没主键或非空唯一键,它产生的所有事务写集都为空,整个通道就会被 coordinator 锁死——这不是 bug,是 MySQL 为一致性做的主动妥协。











