WRITESET并行复制需满足主库启用FULL/MINIMAL row image、从库设LOGICAL_CLOCK、表有主键或唯一非空索引等硬性条件,否则事务退化为串行;其实际效果须通过performance_schema中APPLIED_TRANSACTIONS_IMMEDIATE占比等指标验证。

MySQL 8.0 的 WRITESET 并行复制不是“开个开关就自动变快”,它依赖主库事务的写冲突检测能力,且对表结构有硬性要求——没主键或唯一非空索引的表,事务直接退化为串行回放。
为什么 WRITESET 在大规模集群中仍可能失效
WRITESET 的并行度取决于事务修改的行是否在 writeset 中产生冲突。如果大量事务都更新同一张无主键的大表(比如日志表、埋点表),哪怕分布在不同库,writeset 也会把它们标记为互斥,强制串行执行。
-
binlog_transaction_dependency_tracking必须设为WRITESET或WRITESET_SESSION,不能是默认的COMMIT_ORDER - 从库
slave_parallel_type必须为LOGICAL_CLOCK(WRITESET 是其依赖的依赖追踪方式,不是独立类型) - 主库必须启用
binlog_row_image=FULL或MINIMAL(NONE会丢关键字段,导致 writeset 计算失败) - 表必须有主键,或至少一个
NOT NULL UNIQUE索引;否则 MySQL 无法提取 writeset key,该事务全程单线程回放
如何验证 WRITESET 是否真正生效
不能只看 SHOW SLAVE STATUS 里的 Seconds_Behind_Master 降了就认为 OK。要查从库内部的并行调度统计:
SELECT * FROM performance_schema.replication_applier_status_by_coordinator;
重点看 APPLIED_TRANSACTIONS_TOTAL 和 APPLIED_TRANSACTIONS_IMMEDIATE 的比值。如果后者长期接近 0,说明几乎没并行事务被调度——大概率是 writeset 冲突太多或表缺失主键。
- 用
mysqlbinlog --base64-output=decode-rows -v解析主库 binlog,确认事务 event 中是否含write_set字段 - 检查慢查询日志里是否有大量
ALTER TABLE ... ADD COLUMN或UPDATE全表扫描操作——这类操作会清空 writeset 缓存,后续事务全部串行 - 监控
performance_schema.replication_applier_status_by_worker中各 worker 的LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP是否严重发散(发散越小,并行越均衡)
WRITESET 配合 GTID 使用时的坑
GTID 模式下,WRITESET 要求所有节点开启 enforce_gtid_consistency=ON,且不能有非事务引擎表(如 MyISAM)。一旦出现不一致的 GTID event,从库 SQL 线程会卡住,Seconds_Behind_Master 会跳变为 NULL,而不是缓慢增长。
- 主库执行
DROP TEMPORARY TABLE或CREATE TEMPORARY TABLE会被 GTID 过滤器忽略,但 writeset 仍尝试计算——触发 warning 并降低并行效率 - 跨分片写入(如 sharding-proxy 后写多个库)若未统一使用
WRITESET_SESSION,writeset 会误判跨 session 事务存在冲突,白白牺牲并行度 - 从库重启后首次启动复制时,如果 relay log 中有旧版本 binlog(5.7 或更早),writeset 信息缺失,这部分事务强制串行,直到第一个带 writeset 的事务到达
WRITESET 的价值不在“绝对零延迟”,而在把原本只能靠拆库、加机器解决的延迟问题,压缩到单实例内核级调度层面。但它对建表规范、事务粒度、binlog 格式极其敏感——这些约束条件,比参数本身更值得花时间检查。


















