MySQL 5.7 MTS并行复制需同时满足:slave_parallel_workers>1、slave_parallel_type='LOGICAL_CLOCK'、主库binlog_format='ROW'且binlog_order_commits=ON、从库启用crash-safe表存储及slave_preserve_commit_order=1,缺一不可。

MySQL 5.7 的 MTS(Multi-Threaded Slave)并行复制机制本身能解单线程延迟瓶颈,但默认完全不生效——slave_parallel_workers 默认为 0,slave_parallel_type 默认是 'DATABASE',这两个值组合下来就是纯单线程 SQL 线程回放,和 5.6 一样。
为什么 slave_parallel_workers > 1 却没效果
这个参数不是开关,只是 worker 数量的计数器。它只在 slave_parallel_type = 'LOGICAL_CLOCK' 下才真正启用并行调度:
-
slave_parallel_workers = 0:无 coordinator 架构,纯单线程回放 relay log -
slave_parallel_workers = 1:coordinator 存在但只配一个 worker,事务仍串行;实测比 = 0 还慢约 20% -
slave_parallel_workers > 1且slave_parallel_type != 'LOGICAL_CLOCK':参数被忽略,静默降级为单线程
常见错误现象:SHOW SLAVE STATUS\G 中 Slave_SQL_Running_State 长期卡在 “Reading event from the relay log”,且 SELECT * FROM performance_schema.replication_applier_status_by_worker; 只返回 1 行(WORKER_ID = 1),说明并行根本未启动。
slave_parallel_type = 'LOGICAL_CLOCK' 的硬性前提
该模式依赖主库 binlog 中的 last_committed 和 sequence_number 字段分组事务,缺一不可:
- 主库
binlog_format必须为'ROW'(MIXED在含NOW()、UUID()等非确定函数时会退化为STATEMENT,丢弃组提交信息) - 主库需确认
binlog_order_commits = ON(默认开启,但建议显式执行SET GLOBAL binlog_order_commits = ON;) - 从库必须启用 crash-safe 元数据存储:
SET GLOBAL master_info_repository = 'TABLE';和SET GLOBAL relay_log_info_repository = 'TABLE'; - 从库需设
slave_preserve_commit_order = 1,否则事务提交乱序可能引发数据不一致
注意:slave_parallel_type 不支持热更新,必须停复制后设置。
必须 STOP/START SLAVE 的三步操作顺序
截至 2026 年 10 月,slave_parallel_type 仍无法在线修改。跳过任一步,START SLAVE 可能失败或静默降级:
- 主库先确认:
SET GLOBAL binlog_format = 'ROW';,并检查binlog_row_image = 'FULL'(推荐) - 从库执行:
STOP SLAVE;→SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';→SET GLOBAL slave_parallel_workers = 4;(建议从 4 起步,不超过 CPU 核心数) - 从库必须同步设置:
SET GLOBAL master_info_repository = 'TABLE';、SET GLOBAL relay_log_info_repository = 'TABLE';、SET GLOBAL relay_log_recovery = ON;
做完这三步后,再 START SLAVE,然后立刻查 performance_schema.replication_applier_status_by_worker —— 如果返回多行(WORKER_ID 从 1 到 N),才算真正跑起来了。
最容易被忽略的一点是:即使所有配置都对了,只要有一张表缺主键或唯一索引,Error_code: 1032 就会直接中断并行回放。ROW 格式下,没有主键的 UPDATE/DELETE 会触发全表扫描,而并行线程又可能乱序执行,导致“找不到要更新的那行”。务必用 information_schema 扫一遍无主键表,提前补上。


















