当前位置: 首页 > news >正文

MySQL并行复制原理与调优实战:LOGICAL_CLOCK到WRITESET_SESSION全链路优化

📌今日关键词:MySQL并行复制、主从延迟、LOGICAL_CLOCK、WRITESET、MTS调优

大家好,我是数据库小学妹 👋

之前我们聊过主从同步失败的五大诱因,有粉丝朋友问我:“小学妹,我的从库倒没挂,但 Seconds_Behind_Master 一直飙到几千秒,延迟越来越大怎么办?”

这个问题我太有发言权了。虽然我们讲过主从延迟的5个常见原因和3个排查命令,但那只是入门级别。真正要解决"从库追不上"的问题,得搞懂并行复制这个核心机制。

我一开始以为并行复制就是改个参数的事,设个 slave_parallel_workers 就完事了。结果改完延迟一点没降,还差点搞出数据不一致。后来才明白,MySQL 的并行复制经历了四代演进,每一代的设计思路完全不同,参数之间还有依赖关系。不搞清楚原理就上手调,跟闭眼开车差不多。

今天从单线程为什么慢讲起,把四代演进拆透,再配合排查路径和调优方案,争取看完就能上手。


一、为什么从库会"追不上"主库?

先回忆一下主从复制的基本流程:

主库写入 → binlog → 从库IO线程拉取 → relay log → 从库SQL线程重放 → 数据写入

延迟就卡在最后一步:SQL线程重放。

主库能同时处理几百上千个并发连接,binlog里记录的是所有连接混合在一起的事务。但从库呢?MySQL 5.6之前,只有一个SQL线程在那一条一条地重放。

打个比方:主库是10条流水线同时干活,从库只有1个人在那一件一件地做。主库写得越快,从库就落得越远。

说白了,就是干活的人太少。网络没问题,磁盘也没问题,瓶颈出在重放线程上。


二、并行复制的四代演进

MySQL团队为了解决这个瓶颈,前前后后搞了四代方案。每一代都是在上一代的基础上改的。

第一代:基于Schema的并行(MySQL 5.6)

5.6引入了最早的并行方案:如果两个事务操作的是不同数据库(schema),它们之间没有数据冲突,可以并行执行。

# my.cnf slave_parallel_workers = 4 slave_parallel_type = DATABASE # 基于数据库并行

局限性很大。现在的业务谁不是一个库搞到底?单库多表的场景下,这个方案基本等于没开。十个表都在同一个库里,全部串行。

我当时的项目就是这种情况,一个业务库里40多张表,开了这个参数之后延迟纹丝不动。

第二代:LOGICAL_CLOCK(MySQL 5.7.2+)

这是真正意义上的突破。思路变了:不再看"是不是同一个库",而是看"在主库是不是一起提交的"。

核心机制叫 Group Commit(组提交)。

什么是Group Commit?

MySQL为了减少fsync次数,会把多个事务的binlog攒在一起写盘。比如同一时刻有事务A、B、C都在commit,MySQL会把它们放在一个组里,只做一次fsync。

时间线: t1: 事务A commit → 进入binlog cache t2: 事务B commit → 进入binlog cache t3: 事务C commit → 进入binlog cache t4: 三个事务一起fsync到binlog文件(一次IO搞定)

组提交的关键:同一个组里的事务,在主库就是"同时"提交的,它们之间大概率不冲突。

5.7在binlog里记录了每个事务的"逻辑时钟"(其实就是组提交的序列号)。从库看到两个事务的逻辑时钟相同,就知道它们在主库是同一组提交的,可以并行重放。

# my.cnf slave_parallel_type = LOGICAL_CLOCK slave_parallel_workers = 8 slave_preserve_commit_order = ON

比5.6好在哪?不看数据库了,看主库实际的提交关系。单库多表也能并行。

但也容易踩坑:slave_preserve_commit_order 这个参数一定要开。不开的话,从库事务的提交顺序可能跟主库不一致,某些依赖提交顺序的业务逻辑会出问题。开了会损失一些并行度,但数据安全更重要。

第三代:WRITESET(MySQL 5.7.22+)

LOGICAL_CLOCK的问题在哪?粒度还是太粗。同一个组里的事务数量有限,大部分时间从库的worker还是在等。

WRITESET换了思路:不看"主库什么时候提交",而是看"两个事务操作的数据有没有重叠"。

事务A写了行 {id=1, id=2} 事务B写了行 {id=3, id=4} → A和B的写集合(WRITESET)不相交 → 可以并行!

即使事务A和事务B在主库不是同一个组提交的,只要它们操作的数据不重叠,从库也可以并行执行。

# my.cnf slave_parallel_type = LOGICAL_CLOCK slave_parallel_workers = 8 binlog_transaction_dependency_tracking = WRITESET transaction_write_set_extraction = XXHASH64 slave_preserve_commit_order = ON

并行度比LOGICAL_CLOCK高很多,但也带来了新问题,我们后面展开讲。

第四代:WRITESET_SESSION(MySQL 8.0.27+)

WRITESET的隐患:同一session里的两个事务,如果操作不同行,WRITESET会认为它们不冲突、可以并行。但实际上同一个session的事务是有先后顺序的,乱序可能出问题。

8.0.27加了WRITESET_SESSION:在WRITESET的基础上,保证同一session的事务串行执行,不同session的事务仍然可以按写集合判断并行。

# my.cnf 推荐配置(8.0.27+) binlog_transaction_dependency_tracking = WRITESET_SESSION transaction_write_set_extraction = XXHASH64 slave_parallel_type = LOGICAL_CLOCK slave_parallel_workers = 8 slave_preserve_commit_order = ON

8.0.27+的环境,直接用这个就对了。


三、版本选型对照表

MySQL版本推荐方案关键参数
5.6Schema并行(聊胜于无)slave_parallel_type=DATABASE
5.7.2 ~ 5.7.21LOGICAL_CLOCKslave_parallel_type=LOGICAL_CLOCK
5.7.22 ~ 8.0.26WRITESETbinlog_transaction_dependency_tracking=WRITESET
8.0.27+WRITESET_SESSIONbinlog_transaction_dependency_tracking=WRITESET_SESSION

不管哪个版本,slave_preserve_commit_order 都建议开。


四、并行度怎么设?不是越大越好

slave_parallel_workers 设多少合适?我最初的想法是"越多越好",直接设了32。结果从库CPU飙到100%,锁争用严重,延迟反而更大了。

经验值:

机器配置建议worker数
4核8G4~8
8核16G8~16
16核32G16~32

调优步骤:

  1. 先设8,观察一周
  2. 看从库CPU使用率和延迟趋势
  3. CPU低于60%且延迟还在涨 → 加worker
  4. CPU高于80%或锁争用明显 → 减worker
-- 查看worker状态SELECTworker_id,thread_id,service_state,last_error_number,last_error_messageFROMperformance_schema.replication_applier_status_by_worker;

五、延迟排查路径:四种现象四种打法

并行复制配好了,延迟还是高?下面四种场景,我一个个讲。

场景一:延迟持续增长,越来越大

十个延迟问题里有八个是这种。排查路径:

-- 第一步:看从库在干什么SHOWPROCESSLIST;-- 第二步:看有没有大事务阻塞SELECT*FROMinformation_schema.innodb_trxWHEREtrx_started<NOW()-INTERVAL30SECONDORDERBYtrx_started;-- 第三步:看从库锁等待SELECT*FROMperformance_schema.data_lock_waits;

常见原因:

  • 主库有大事务(DELETE几百万行、ALTER大表)
  • 从库IO慢,relay log写入跟不上
  • 并行复制没开或者配错了

解法就是大事务拆小批量执行,IO慢就换SSD,并行复制参数按上面配。

场景二:延迟抖动,一阵一阵的

延迟不是持续增长,而是每隔几分钟飙一次,然后又慢慢降下来。

排查方向:

  • 定时任务(每5分钟的批量写入)
  • 监控/备份脚本(mysqldump、xtrabackup跑的时候IO飙升)
  • 主库的checkpoint

这种场景通常是业务层的写入不均匀导致的。

场景三:Seconds_Behind_Master=0,但业务读到老数据

这个最坑。监控看着一切正常,延迟为0,但业务就是查不到新数据。

-- 用performance_schema看真实延迟SELECT*FROMperformance_schema.replication_applier_status;-- 或者用心跳表对比-- 主库写入当前时间UPDATEheartbeatSETts=NOW(6)WHEREid=1;-- 从库读取对比SELECTTIMESTAMPDIFF(SECOND,ts,NOW(6))ASreal_lagFROMheartbeatWHEREid=1;

Seconds_Behind_Master是基于binlog里TIMESTAMP字段计算的,当某些事务不包含时间戳信息时,这个指标会显示0,但实际延迟可能存在。

解法就是上心跳表做业务级监控,比Seconds_Behind_Master靠谱得多。

场景四:延迟突然归零又涨上去

通常是某个大事务执行完了,SQL线程瞬间追上,然后下一个大事务又开始堆积。

看relay log空间能辅助判断:

SHOWSLAVESTATUS\G-- 看 Relay_Log_Space 字段-- 如果一直在涨,说明IO线程拉的比SQL线程放的快

六、业务层调优:光调数据库参数不够

并行复制能解决SQL线程串行的瓶颈,但有些问题光靠参数搞不定。

拆大事务

大事务是延迟的头号杀手。

-- 错误写法:一次删100万行DELETEFROMlogsWHEREcreated_at<'2024-01-01';-- 正确写法:分批删除DELETEFROMlogsWHEREcreated_at<'2024-01-01'LIMIT10000;-- 应用层循环执行,每批之间sleep(1)

我之前接手的一个项目,开发同学写了个定时清理任务,每个月删3000万行日志,一个DELETE搞定。跑了两个月我才发现从库延迟经常飙到1小时。改成每批5000行、间隔0.5秒之后,延迟从没超过10秒。

大表DDL用工具

-- 错误写法:直接ALTERALTERTABLEbig_tableADDCOLUMNxINT;-- 正确写法:用gh-ost或pt-online-schema-change-- gh-ost不会长时间锁表,对复制友好

读写分离要注意"读后写"

开了读写分离之后,如果有业务逻辑是"先SELECT再UPDATE",SELECT走从库可能读到老数据,UPDATE走主库写了新数据,中间就出问题了。

要么在代码里强制这类查询走主库,要么用中间件(ProxySQL)配置规则把这类SQL路由到主库。


七、监控方案:光看一个指标不够

复制状态监控

-- 最基础:SHOW SLAVE STATUSSHOWSLAVESTATUS\G-- 关注:Slave_IO_Running, Slave_SQL_Running, Seconds_Behind_Master-- 更准确:performance_schemaSELECT*FROMperformance_schema.replication_connection_status\GSELECT*FROMperformance_schema.replication_applier_status\G

业务延迟监控

心跳表方案:

-- 在monitor库建心跳表CREATETABLEheartbeat(idINTPRIMARYKEY,tsTIMESTAMP(6)DEFAULTCURRENT_TIMESTAMP(6)ONUPDATECURRENT_TIMESTAMP(6));INSERTINTOheartbeat(id)VALUES(1);

后台任务每秒在主库UPDATE心跳表的ts字段,然后对比主从ts差值。这个差值就是真实延迟。比Seconds_Behind_Master准确,不依赖binlog里的时间戳。


八、升级5.7到8.0的并行复制变化

如果你的环境在做5.7→8.0升级,并行复制方面有几个点要注意:

变化说明
WRITESET_SESSION8.0.27+新增,比WRITESET更安全,推荐开启
命令语法更新SHOW SLAVE STATUS → SHOW REPLICA STATUS(8.0.22+兼容老语法)
redo log格式变化8.0 redo log格式有调整,升级后需重新调innodb_redo_log_capacity
认证插件变更caching_sha2_password是8.0默认,从库连主库要确认密码插件兼容

升级后的推荐配置:

# 8.0.27+ 推荐 binlog_transaction_dependency_tracking = WRITESET_SESSION transaction_write_set_extraction = XXHASH64 slave_parallel_type = LOGICAL_CLOCK slave_parallel_workers = 8 slave_preserve_commit_order = ON innodb_redo_log_capacity = 4294967296 # 4GB,单位字节

九、面试怎么答

面试官:MySQL并行复制经历了哪几个阶段?各自原理是什么?

并行复制经历了四个阶段。5.6是基于Schema的并行,不同数据库的事务可以同时执行,但单库场景没用。5.7.2引入LOGICAL_CLOCK,利用主库的Group Commit机制,同组提交的事务可以在从库并行重放。5.7.22进一步引入WRITESET,通过分析事务的写集合判断是否冲突,不冲突就并行,粒度更细。8.0.27加了WRITESET_SESSION,在WRITESET基础上保证同一session事务串行,避免乱序问题。生产里建议8.0.27+直接用WRITESET_SESSION。

面试官:slave_preserve_commit_order为什么建议开启?

并行重放后,从库事务的提交顺序可能跟主库不一致。如果业务逻辑依赖提交顺序(比如先插入后更新的时序),不开启可能导致数据不一致。开启后会损失一部分并行度,但换来的是数据安全性。生产环境建议始终开启。

面试官:Seconds_Behind_Master为0但业务读到老数据,怎么排查?

Seconds_Behind_Master基于binlog中的TIMESTAMP字段计算,当事务不包含时间戳时会显示0。先用performance_schema的replication_applier_status查真实状态,再上心跳表做业务级监控——主库每秒写入当前时间到心跳表,从库读取对比差值,这个差值就是真实延迟。


避坑清单

序号坑点后果正确做法
1不开并行复制就指望延迟自己降延迟随写入量线性增长5.7+至少用LOGICAL_CLOCK
2slave_parallel_workers设太大CPU飙高、锁争用严重从8开始,观察后再调
3不开slave_preserve_commit_order从库提交顺序错乱,数据不一致生产环境必须ON
4WRITESET模式下同一session事务冲突从库数据错乱或报错8.0.27+用WRITESET_SESSION
5只看Seconds_Behind_Master指标失真以为没延迟上心跳表+performance_schema
6主库跑大事务不拆分从库阻塞几十分钟分批执行,每批LIMIT控制行数
7大表直接ALTER不走工具复制延迟飙升、锁表用gh-ost或pt-osc
8读写分离不考虑"读后写"业务读到旧数据做错误写入关键查询路由到主库
9升级8.0后不调redo log参数redo log格式变化导致IO异常升级后调innodb_redo_log_capacity
10以为调参数就能解决所有延迟忽略业务层大事务、定时任务等根因参数+业务双管齐下

总结

并行复制不是"改个参数就完事"的事。四代演进下来,每一代解决了不同层面的问题:

  • 5.6 Schema并行 → 解决"完全没有并行"
  • 5.7 LOGICAL_CLOCK → 利用组提交实现真正的并行
  • 5.7.22 WRITESET → 通过写集合分析,粒度更细
  • 8.0.27 WRITESET_SESSION → 兼顾并行度和session顺序

但并行复制只解决SQL线程的瓶颈。真正要做到延迟可控,还得在业务层把大事务拆掉、定时任务分批跑、读写分离路由做对。

并行复制解决"干活的人少"的问题,业务优化解决"活太大"的问题。两个都搞定,从库追不上主库的问题基本就治好了。

我是数据库小学妹,咱们下篇见 👋

http://www.jsqmd.com/news/974611/

相关文章:

  • 基于PWM与中断的软件UART实现:以MMC2001为例的嵌入式通信方案
  • 嵌入式Linux远程调试实战:基于i.MX 8M的GDB与IDE配置指南
  • AsrTools:高效语音转文字解决方案,简化音频内容处理流程
  • 避开回收陷阱!2026大同各区黄金回收正规门店明细及实测 - 余生黄金回收
  • C#逆向工具横评:除了dotPeek,dnSpy/ILSpy/.NET Reflector到底怎么选?附实战场景分析
  • 12个Chrome插件:机器学习工程师的浏览器效率中枢
  • 实用影响分析:从技术变更到业务代价的因果链建模
  • 曲阜母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 绿呼吸检测中心
  • S32M244 FTM/PDB/ADC协同配置实现无感PMSM FOC硬件触发链路
  • 基于LPC5460x与LVGL的嵌入式GUI开发实战:从可视化设计到性能优化
  • 5分钟快速上手:HS2-HF Patch终极汉化与去码增强指南
  • 武汉云克隆Luminex多因子检测骨代谢多标志物(ACP5、ALPL、CTXI、DKK1、IL6、LEP、OC、OPG、OPN、PDGF BB、PINP等),引领骨骼研究,守护骨骼健康
  • 基于56F8300的EMB系统PMSM矢量控制全流程工程实践解析
  • SMUDebugTool:深度掌控AMD Ryzen处理器的完整调试指南
  • LPC86x FTM同步机制详解:实现无毛刺PWM动态更新
  • 2026扬州贵金属回收避坑指南 正规门店大盘价回收汇总 - 余生黄金回收
  • MC68HC11长波无线电数据解码器:从BBC信号中提取精准时间的嵌入式系统设计
  • 嵌入式DSP实时内存管理:VSMM原理、配置与工程实践指南
  • MC9S08PB16硬件互连实现纳秒级过流保护:OPAMP、ACMP与FDS实战
  • 大同市黄金回收探店实测:六家店真实回收体验全记录 - 余生黄金回收
  • 打破语言壁垒:3分钟掌握Translumo实时屏幕翻译工具
  • 3个实战技巧:用ITK-SNAP精准解决医学图像分割难题
  • 深入YOLOv5的‘骨架’与‘神经’:从模型yaml文件到训练超参的完整配置解析
  • 三维空间直线怎么表示?用Python手把手实现普吕克坐标(附完整代码)
  • OpenSeesPy结构分析实战指南:Python有限元建模的5个高效方法
  • 2026年汕头黄金回收套路拆解:六大渠道逐项实测,950元/克行情下看清每一个坑 - 余生黄金回收
  • 如何在Android设备上实现专业级FT8通信?FT8CN开源项目实战指南
  • IPXWrapper技术解析:现代Windows系统下的IPX/SPX协议兼容解决方案
  • 清远母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 绿呼吸检测中心
  • i.MX RT500 FRO-250M时钟升级:低功耗MCU性能跃迁实战指南