开放问答
MySQL 8.0 批量 UPDATE 50 万行导致从库延迟 20 分钟,ROW 格式下如何拆分或规避
该问题的正文、回答与评论。
提问者 陈亦舟 · 状态 open
MySQL主从延迟大事务binlog性能调优
背景
MySQL 8.0.32,一主一从架构,binlog_format=ROW,从库已开并行复制(slave_parallel_workers=8,slave_parallel_type=LOGICAL_CLOCK)。业务表 t_settlement 约 8000 万行,InnoDB,主键 id,业务键 order_no(唯一索引)。
现象
业务侧一个定时任务执行:
UPDATE t_settlement
SET status = 'PAID'
WHERE status = 'PENDING'
AND settle_time < NOW() - INTERVAL 3 DAY;
单次影响约 45–55 万行。从库 Seconds_Behind_Master 从 2s 飙到 1200s+,持续约 20 分钟才追平。期间从库上 read-only 的查询接口 P99 从 15ms 涨到 300ms+,replay 线程把 CPU 打满。
已尝试的排查与结果
- 拆批 + sleep:把 UPDATE 拆成 5 批,每批
LIMIT 100000,批间SLEEP(2)。从库延迟仍出现 8–12 分钟尖峰,峰值降低了但窗口没缩。 - 加大并行度:slave_parallel_workers 从 4 调到 16,效果不明显——瓶颈明显在单表的行锁串行。
- 考虑 DELETE + INSERT 两阶段:担心 binlog 体积翻倍、主库写放大,没敢上线。
期望得到的答案
- ROW 格式下,大事务的 binlog 事件在从库 apply 时到底是怎么调度的?为什么
parallel_type=LOGICAL_CLOCK对单表大事务帮助有限? - 有没有比"拆批 + sleep"更优雅的方式?比如 pt-osc 风格的影子表方案、event scheduler 驱动的小事务、或者直接用
pt-online-schema-change的思路改写? - 如果最终还是走拆批路线,批粒度(每批多少行)和批间间隔有没有可量化的估算方法,而不是拍脑袋给个 LIMIT?
我关心的是可落地的操作方案 + 背后的原理,而不是"加机器"或"上分库"。
评论
暂无评论。