WRITESET能绕过5.7组提交瓶颈,因其不依赖主库“凑组”,而是基于事务修改行的主键/唯一键哈希生成write_set集合,从库通过集合交集判断行级冲突,无交集即并发执行,使时间分离但行不重叠的事务也能并行。

WRITESET 为什么能绕过 5.7 的组提交瓶颈
MySQL 5.7 的 LOGICAL_CLOCK 并行复制依赖主库是否“凑组”——只有同一刷盘批次的事务才共享相同的 last_committed 值,从库才能分发给多个 worker。但单线程写入、定时任务批量更新单表、低峰期流量稀疏时,last_committed 几乎总是递增,SQL 线程实际退化为串行。
WRITESET 不看时间先后,只看行级冲突:每个事务在主库提交前,会基于其修改行的主键或唯一键值计算哈希,生成一个 write_set 集合(如 {hash(users:101), hash(orders:202)}),随 binlog 一起传到从库。从库用集合交集判断并行性——无交集就并发执行。
- 两个相隔 3 分钟提交的
UPDATE,只要改的是不同行,就能被调度进同一批worker - 即使所有 DML 都落在同一张表、同一个库,只要行不重叠,照样并行
- 不再受
binlog_group_commit_sync_delay这类调优参数绑架,业务流量变化时仍稳定生效
配置 WRITESET 必须对齐的三项关键参数
WRITESET 是主从协同机制,缺一不可。常见错误是只改主库或只改从库,结果 Seconds_Behind_Master 依然居高不下。
- 主库必须设:
binlog_transaction_dependency_tracking = WRITESET(默认是COMMIT_ORDER,不设就无效) - 主库
binlog_format必须为ROW(MIXED在部分场景下可能 fallback 到STATEMENT,导致write_set缺失) - 从库必须设:
slave_parallel_type = LOGICAL_CLOCK(注意:不是WRITESET;WRITESET是 dependency tracking 模式,不是parallel_type)
漏掉任意一项,从库 SQL 线程仍按旧逻辑串行回放,SHOW PROCESSLIST 中 Slave_SQL_Running_State 会长时间卡在 Waiting for an event from Coordinator。
GTID + WRITESET 组合如何减少人工干预延迟
MySQL 8.0 强制推荐 gtid_mode = ON,配合 enforce_gtid_consistency = ON。当从库 SQL 线程因唯一键冲突、表不存在等错误中断时,不再需要手动解析 relay log 找 position、执行 CHANGE MASTER TO RELAY_LOG_FILE=... POS=...。
- 直接执行:
SET GTID_NEXT = 'xxx-xxx-xxx:12345'; BEGIN; COMMIT;即可跳过单个事务 - 跳过后,GTID 自动对齐后续事务,整个过程秒级完成
- 重启从库后,
GTID_EXECUTED自动识别已执行事务,无需依赖MASTER_AUTO_POSITION = 1以外的起点同步方式
但务必确认该事务在业务上可丢弃(比如幂等更新失败),且跳过前用 SELECT GTID_SUBSET('xxx-xxx-xxx:12345', GTID_EXECUTED) 校验目标 GTID 是否尚未执行,否则可能引发数据错乱。
容易被忽略的隐性风险点
WRITESET 本身不慢,但配置不当或环境不匹配时,反而放大延迟。最常被忽视的是:
-
slave_preserve_commit_order = ON(MySQL 8.0 默认开启):它保障事务提交顺序不被并行打乱,但若某事务依赖前序事务结果(如触发器跨表更新),强制保序会让 worker 等待,实际吞吐下降 -
slave_parallel_workers设太高(比如 > CPU 核数 × 2):IO 或锁竞争加剧,Performance_schema中可见大量wait/io/file/innodb/innodb_data_file等待 - 主库未建主键或唯一键的表:WRITESET 无法生成有效哈希,这类表上的事务自动降级为串行回放
真正起效的前提,是主库每张参与复制的表都有明确的主键或唯一键——没有这个,write_set 就是空集,从库只能保守串行。


















