小时级延迟应先查因再决策:立即执行SHOW SLAVE STATUS\G确认IO/SQL线程状态、Relay_Log_Pos是否停滞,并用mysqlbinlog解析relay log定位卡点,而非盲目STOP SLAVE或停写。

延迟已到小时级,先停写还是先查因?
小时级延迟说明从库 SQL 线程已严重积压,此时继续往主库写入只会雪上加霜。但盲目 STOP SLAVE 也不行——它不释放 relay log 文件,且重启后仍要重放全部积压事务,耗时可能更长。
正确动作是:立即在从库执行 SHOW SLAVE STATUS\G,重点看 Seconds_Behind_Master(此时大概率显示 NULL 或极大值)、Relay_Log_Pos 是否停滞、SQL_Delay 是否被误设。同时用 mysqlbinlog --base64-output=DECODE-ROWS -v 解析最新 relay log,确认最后执行的事务是否卡在某个大表更新或 DDL 上。
- 若
Relay_Log_Pos完全不动,优先检查 IO 线程是否异常(Slave_IO_Running: No),再查网络或主库 binlog 是否中断 - 若
Relay_Log_Pos缓慢前进,但Seconds_Behind_Master持续飙升,基本可判定为 SQL 线程回放瓶颈,进入下一步 - 跳过临时性大事务不可取——除非业务允许丢数据,否则跳过会破坏 GTID 一致性,后续无法自动修复
快速清空积压:绕过 SQL 线程直接应用 relay log
当积压量过大(比如 relay log 超过 50GB),原生 SQL 线程单线程回放可能需要数小时。这时可改用 mysqlbinlog + mysql 组合,将 relay log 转为 SQL 流并行导入(需确保事务间无强依赖)。
操作前必须满足:主从已开启 binlog_format=ROW,且 relay log 中不含 DDL(或已人工剥离);否则解析出的 SQL 会报错或破坏结构。
- 提取 relay log 内容:
mysqlbinlog --skip-gtids --database=mydb /var/lib/mysql/mysql-relay-bin.000123 > /tmp/relay.sql - 拆分大文件(避免 OOM):
split -l 50000 /tmp/relay.sql /tmp/relay_part_ - 并发导入(注意控制连接数,避免打爆从库):
mysql -u root mydb - 完成后手动重置复制位点:
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000456', MASTER_LOG_POS=123456789;
MySQL 5.7+ 必开的三项动态参数
小时级延迟几乎一定暴露了并行复制未启用或配置过低。不要等重启,立刻在从库执行以下命令(需 SUPER 权限):
STOP SLAVE;-
SET GLOBAL slave_parallel_type='LOGICAL_CLOCK';(MySQL 5.7+ 必须设此项,DATABASE类型对单库无效) -
SET GLOBAL slave_parallel_workers=16;(建议设为 CPU 逻辑核数的 75%,超 16 反而易争抢) -
SET GLOBAL slave_preserve_commit_order=ON;(保证事务提交顺序,避免主从不一致) START SLAVE;
注意:slave_parallel_workers 设为 0 会退化为单线程;设得过高(如 32)在 SSD 上反而因上下文切换增加开销。实测中,16 工作线程在 16 核机器上回放速度提升约 4.2 倍。
为什么调大 innodb_buffer_pool_size 反而让延迟更糟?
这是最容易踩的坑:看到从库内存占用不高,就盲目把 innodb_buffer_pool_size 从 60% 提到 85%,结果延迟不降反升。原因在于——从库大量执行的是随机读(根据主键回放 UPDATE/DELETE),而非主库的顺序写。buffer pool 过大会挤占 OS page cache,导致 relay log 文件读取变慢,IO 等待飙升。
真实有效的做法是:保留 buffer pool 在物理内存的 60%~70%,同时用 iostat -dx 1 观察 await 和 %util。若 await > 15ms 且 %util > 90%,说明磁盘已是瓶颈,此时该换 NVMe,而不是调 buffer pool。
另一个常被忽略的点:innodb_io_capacity 和 innodb_io_capacity_max 必须匹配硬件。SSD 建议设为 2000/4000,NVMe 则应调至 8000/16000。设低了,InnoDB 主动限速;设高了,又可能引发 IO 飙升拖垮系统。


















