编程 改了 replica_parallel_workers 却没生效:MySQL 多线程复制参数的生效时机、互斥与边界

2026-11-14 00:04:31

改了 replica_parallel_workers 却没生效:MySQL 多线程复制参数的生效时机、互斥与边界

执行 SET GLOBAL replica_parallel_workers=16 之后,performance_schema 里的 worker 还是 4 行——因为没有执行过 STOP REPLICA 和 START REPLICA;如果重启过实例,而配置文件里没写这一项,它就会回到默认的 4。另一种情况则更令人困惑:为了“稳妥”,把它设成 1,结果无论怎么配置 replica_parallel_type 和 replica_preserve_commit_order 都没有反应。这两个现象不是 bug,而是因为这几个参数的生效时机和互斥关系各不相同。

replica_parallel_workers:只对下一次 START REPLICA 生效

  • 默认值 4(8.0.27 起),8.0.26 及之前默认 0;范围 0–1024,整数。
  • 值 ≥1 时是“N 个 worker + 1 个 coordinator”;值为 0 时只有一个线程顺序读写并应用。
  • 8.0.30 起,设为 0 已弃用,会产生告警并将在未来移除;只想要单线程应设 1。
  • 设为 1 时是 coordinator + 1 个 worker 顺序应用,此时 replica_parallel_type 与 replica_preserve_commit_order 被忽略,配了也不起作用——这就是开头第二个现象的来源。
  • 若 replica_parallel_workers=0 且该 channel 开了 GTID_ONLY=1,副本实际使用 1 个 worker,等价于设为 1:多线程 applier 靠保存的位点而非元数据库定位要重放的事务。
  • 修改后无立即效果,只对所有后续 START REPLICA 生效。改完变量不重启 apply 线程,看多少遍状态都还是老值。
  • 多 channel 时该值对每个 channel 各生效一次:N 个 channel 就是 N×(workers+1) 个线程,线程数要按 channel 数相乘算。
  • 表无主键时,workers>1 的负面影响更大。

replica_checkpoint_group 与 replica_checkpoint_period:一个等 START,一个立即生效

replica_checkpoint_group:

  • 默认 512;最小 32(debug 构建为 1);最大 524280;block size 8,实际值向下取整到 8 的倍数(debug 构建不取整)。
  • 含义是多线程副本处理多少事务后触发一次 checkpoint,更新 SHOW REPLICA STATUS 里显示的状态。
  • 设置后无立即效果,只对后续 START REPLICA 生效。

replica_checkpoint_period:

  • 默认 300(毫秒);最小 1(debug 构建为 0);最大 4294967295 ms。
  • 设置后对所有复制 channel 立即生效,包括正在运行的 channel。

两者配合的方式是:任一超限即执行 checkpoint,并把事务计数与时间计数清零。所以只调 group 不重启 apply 线程时,看到的是“period 改了立刻变、group 改了没动静”的半生效状态。

replica_parallel_type 与 preserve_commit_order:有约束,且必须停 apply 线程

replica_parallel_type 自 8.0.29 起弃用(DATABASE 策略与按库并行一起弃用,未来只保留 LOGICAL_CLOCK);8.4 手册仍标 Deprecated 并给默认值 LOGICAL_CLOCK;WL#13955(Remove replica_parallel_type)已在后续分支移除该变量与 DATABASE 策略,具体落地版本以 release notes 为准。

约束在于:replica_preserve_commit_order=ON 要求 LOGICAL_CLOCK。改这两个参数之前必须停 apply 线程,不能在线热改。

版本移除带来的启动失败

8.3.0 移除了 transaction_write_set_extraction;8.4.0 移除了 binlog_transaction_dependency_tracking。老 my.cnf 里残留这两个键,升级后启动直接失败(unknown variable);巡检脚本里对它们做 SET GLOBAL 会报 1193 Unknown system variable。

检查:把 channel 数乘进去

先确认变量的实际取值:

SHOW VARIABLES LIKE 'replica_parallel_workers';
SHOW VARIABLES LIKE 'replica_checkpoint%';
SHOW VARIABLES LIKE 'replica_parallel_type';
SHOW VARIABLES LIKE 'replica_preserve_commit_order';

再看真正跑起来的 applier 线程数。coordinator 与 worker 分属两张表,replication_applier_status_by_worker 里按 channel 分组统计:

SELECT CHANNEL_NAME, COUNT(*) AS worker_threads
FROM performance_schema.replication_applier_status_by_worker
GROUP BY CHANNEL_NAME;

SELECT COUNT(DISTINCT CHANNEL_NAME)                  AS channels,
       COUNT(*)                                      AS worker_threads,
       COUNT(*) + COUNT(DISTINCT CHANNEL_NAME)       AS applier_threads
FROM performance_schema.replication_applier_status_by_worker;

两个 channel、replica_parallel_workers=4,期望是 2 组、每组 4 个 worker,加上 2 个 coordinator 共 10 个 applier 线程。只按单 channel 估算,线程数和内存都会算错。

状态与位点仍从 SHOW REPLICA STATUS 取:

SHOW REPLICA STATUS\G

重点看 Replica_SQL_Running_State 与 Exec_Master_Log_Pos——MTS 上后者的更新受 gap 影响,见下一节。

gap、STOP 与 RESET 的边界

  • MTS 上停止复制可能留下事务序列 gap(正常停也一样);存在 gap 时 CHANGE REPLICATION SOURCE TO 会失败,需 START REPLICA UNTIL SQL_AFTER_MTS_GAPS 补齐。
  • 8.0.26 起,GTID + auto-positioning 场景跳过 gap 检查。
  • STOP REPLICA 在 MTS 上会等 gap 补齐后才更新 Exec_master_log_pos;若 relay log 末尾事务只收到一半且 coordinator 已开始调度,最多等 60 秒后放弃。
  • RESET REPLICA 会删 relay log 并清位点,有 gap 时等于丢掉 gap 信息;基于 file position 的复制此后恢复会失败。
  • relay_log_recovery 默认 OFF,需在启动参数里给。
  • sync_relay_log=1 对 MTS 尤其重要:gap 无法用 relay log 补齐时恢复会失败。

一条可执行的判据

workers>1 时,performance_schema.replication_applier_status_by_worker 的行数应等于「channel 数 × replica_parallel_workers」,coordinator 不在这张表里。如果对不上,先别怀疑并行度策略,回头确认是否真的执行过一次 STOP REPLICA + START REPLICA——replica_parallel_workers 和 replica_checkpoint_group 都只认下一次 START REPLICA,只有 replica_checkpoint_period 是改完立即生效的。

推荐文章

程序员茄子在线接单