mysql 8.0默认commit_order并发差,因其仅依提交时间判断依赖,不检测行级冲突;writeset通过记录事务修改的行哈希实现真正行级并行,需主库设binlog_transaction_dependency_tracking=writeset、row格式及唯一键支持。

MySQL 8.0 默认用 COMMIT_ORDER,但想真正压榨并行度,必须切到 WRITESET;否则 slave_parallel_workers 再高也白搭。
为什么默认的 COMMIT_ORDER 并发效果差
COMMIT_ORDER 仅靠事务提交时间窗口重叠来判断是否可并行,对同一会话内串行执行的事务(比如一个连接里连续 update user 表、再 update order 表)完全无法拆解——它们会被视为强依赖,只能排队执行。这在 OLTP 场景下非常常见,导致 slave_parallel_workers 设置为 8 也跑不满 2 个线程。
根本原因:它不看“改了哪几行”,只看“啥时候提交”。而真实冲突只发生在写同一行时。
- 现象:
SHOW SLAVE STATUS\G中Slave_SQL_Running_State长期卡在Waiting for preceding transaction to commit,即使Seconds_Behind_Master很小 - 验证:查
performance_schema.replication_applier_status_by_coordinator,看WORKERS_PROCESSED和WORKERS_WAITING比例是否严重失衡 - 限制:该模式下
replica_preserve_commit_order = ON(8.0.27+ 默认)会进一步强制串行化,放大瓶颈
WRITESET 是什么,以及怎么启用它
binlog_transaction_dependency_tracking = WRITESET 让主库在 binlog 里为每个事务记录其修改的行级哈希(writeset),从库据此判断两个事务是否真的写同一行——只要 writeset 无交集,就允许并行回放,哪怕它们来自同一个 session、同一个 database。
这是 MySQL 8.0 实现高并发复制的核心机制,也是 slave_parallel_workers 能起效的前提。
- 主库必须开启:
SET PERSIST binlog_transaction_dependency_tracking = 'WRITESET';(或写入 my.cnf 的[mysqld]段) - 主库 binlog 格式必须是
ROW,且建议已启用 GTID(gtid_mode = ON) - 从库无需额外配置 writeset 相关参数,只要主库写了,它就能读;但必须设
slave_parallel_type = LOGICAL_CLOCK(8.0 默认已是) - 注意:
WRITESET依赖唯一键(PRIMARY KEY / UNIQUE KEY)生成哈希,若表无任何唯一索引,会自动退化为COMMIT_ORDER
WRITESET_SESSION 和 WRITESET 有啥区别
WRITESET_SESSION 是 WRITESET 的增强版:它在 writeset 基础上,额外保证同一 session 内的事务按原始顺序提交。适用于那些业务逻辑强依赖单会话内事务顺序的场景(比如某些金融批处理)。
但它牺牲了部分并行度——同一 session 的事务仍会串行,只是不同 session 之间可以跨行并行。
- 选
WRITESET:追求最大吞吐,能接受从库短暂出现与主库不一致的中间态(如 SELECT 结果顺序差异) - 选
WRITESET_SESSION:需保 session 级一致性,且业务明确要求单连接内事务不可乱序 - 别选
COMMIT_ORDER:除非你确认主库几乎全是跨库操作,或复制延迟根本不敏感 - 运行时切换:
SET PERSIST binlog_transaction_dependency_tracking = 'WRITESET_SESSION';,主库重启后生效
调完之后必须盯住的三个指标
WRITESET 开启后,并非一劳永逸。它引入新维度的依赖计算,也会带来开销和边界问题。
- 看主库性能:监控
Com_begin和Com_commit之间延迟是否明显上升,binlog_transaction_dependency_tracking计算 writeset 会增加少量 CPU 开销 - 看从库并行效率:查
performance_schema.replication_applier_status_by_worker,重点关注LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP分布是否离散——越分散,说明并行越充分 - 看退化信号:如果发现大量事务的
LAST_COMMITTED值等于SEQUENCE_NUMBER - 1(即几乎每个事务都紧挨前一个),说明 writeset 生效失败,大概率是表缺失唯一键,得补索引
真正难的不是打开开关,而是确认 writeset 真正在起作用,且没因表结构缺陷悄悄退化。上线前务必用真实业务流量压测,而不是只看 SHOW SLAVE STATUS 里 SQL_Thread 数字变多了。











