引言
在 MySQL 主从复制架构中,relay log(中继日志)是连接主库与从库数据一致性的关键纽带。很多开发者和运维人员在遇到主从延迟、复制中断时,往往第一时间去检查 binlog 或网络,却忽略了 relay log 这个“中间站”。本文将从 relay log 的本质作用出发,结合常见复制中断场景,给出一套可落地的排查思路。这也是 MySQL 面试中高频出现的考点,理解透彻能让你在面试和实战中都游刃有余。

一、relay log 是什么?为什么需要它?
1.1 基本定义
relay log 是从库(slave/replica)特有的一种日志文件,由从库的 I/O 线程负责写入。它记录了从主库 binlog 中读取到的所有事件(event),本质上就是主库 binlog 在从库上的“本地副本”。
1.2 工作流程
MySQL 主从复制涉及三个核心线程:
- 主库 dump 线程:监听 binlog 变化,将事件发送给从库。
- 从库 I/O 线程:接收主库发来的事件,写入 relay log。
- 从库 SQL 线程:读取 relay log 中的事件,在从库上重放(apply)。
流程可以简化为:
主库 binlog → dump线程 → 网络传输 → 从库I/O线程 → relay log → 从库SQL线程 → 从库数据
1.3 relay log 的核心作用
- 解耦网络传输与 SQL 重放:I/O 线程只需快速接收并落盘,SQL 线程可以按自己的节奏重放,两者互不阻塞。
- 断点续传的基础:从库通过
relay-log.info记录已重放的位置,即使 SQL 线程中断,重启后也能从正确位置继续。 - 数据安全缓冲:当从库 SQL 线程因锁冲突、大事务等原因延迟时,relay log 可以暂存事件,避免数据丢失。
- 支持多线程复制:在并行复制(MTS)模式下,relay log 中的事件按逻辑时钟分组,供多个 worker 线程并发重放。
二、relay log 相关参数与文件结构
常用参数:
| 参数 | 说明 |
|---|---|
relay_log |
指定 relay log 文件名(默认 hostname-relay-bin) |
relay_log_purge |
是否自动清理已重放的 relay log,默认 ON |
relay_log_recovery |
崩溃恢复时是否自动从 SQL 线程位置重新拉取,建议 ON |
max_relay_log_size |
单个 relay log 大小上限 |
sync_relay_log |
每次写入后是否刷盘,1 为最安全 |
文件结构通常包括:
relay-bin.000001、relay-bin.000002……:实际的 relay log 文件。relay-bin.index:索引文件,记录所有 relay log 列表。relay-log.info:记录当前 I/O 线程和 SQL 线程的位置(MySQL 8.0 后逐步被mysql.slave_relay_log_info表替代)。
三、复制中断的常见原因分类
复制中断通常表现为 Slave_SQL_Running: No 或 Slave_IO_Running: No。排查前先执行:
SHOW SLAVE STATUS\G
重点关注:
Slave_IO_Running/Slave_SQL_RunningLast_IO_Error/Last_SQL_ErrorSeconds_Behind_MasterRelay_Log_File/Relay_Log_PosRelay_Master_Log_File/Exec_Master_Log_Pos
3.1 I/O 线程中断
常见原因:
- 网络不通或防火墙拦截。
- 主库 binlog 被清理,从库请求的位置已不存在(
Could not find first log file name)。 - 主从
server_id冲突。 - 账号权限不足或密码错误。
3.2 SQL 线程中断
常见原因:
- 主键冲突 / 唯一键冲突(1062):从库已有相同数据。
- 找不到记录(1032):从库缺少主库要更新/删除的行。
- 表不存在(1146):主从表结构不一致。
- 字段不存在或类型不匹配:DDL 未同步。
- 大事务导致延迟:relay log 堆积,SQL 线程长时间未推进。
四、基于 relay log 的排查实战
4.1 定位当前重放位置
SHOW SLAVE STATUS\G
-- 关注 Relay_Log_File 和 Relay_Log_Pos
使用 mysqlbinlog 解析 relay log,查看具体事件:
mysqlbinlog --base64-output=decode-rows -v \
/var/lib/mysql/relay-bin.000005 > relay_decode.sql
在输出中搜索 Last_SQL_Error 提示的 position,定位到出错的具体 SQL。
4.2 典型场景:1032 错误排查
假设 Last_SQL_Error 提示:
Could not execute Update_rows event on table db.t1;
Can't find record in 't1', Error_code: 1032
步骤:
- 记录
Relay_Log_File与Relay_Log_Pos。 - 用
mysqlbinlog解析该 relay log,找到对应 event。 - 对比主库该行数据与从库该行数据,确认缺失原因。
- 处理方式:
- 若是可忽略的数据不一致,可临时跳过:
STOP SLAVE SQL_THREAD; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE SQL_THREAD; - 若是数据确实缺失,手工补数据后再启动。
- 更稳妥的方式:用
pt-slave-restart或pt-table-sync工具修复。
- 若是可忽略的数据不一致,可临时跳过:
4.3 典型场景:relay log 损坏
若 relay log 文件损坏,SQL 线程可能报错无法读取。此时可:
STOP SLAVE;
RESET SLAVE; -- 清空 relay log
CHANGE MASTER TO ...; -- 重新指定主库位置
START SLAVE;
注意:RESET SLAVE 会删除所有 relay log,务必先确认可重新从主库拉取。
4.4 大事务导致 relay log 暴涨
当主库执行大事务(如一次性更新百万行),relay log 会迅速膨胀,SQL 线程重放缓慢。排查:
SHOW SLAVE STATUS\G
-- 观察 Relay_Log_Space 是否持续增长
解决思路:
- 拆分大事务为小批量。
- 开启并行复制(
slave_parallel_workers > 0)。 - 调整
relay_log_purge与磁盘容量。
五、面试高频问答
Q1:relay log 和 binlog 有什么区别?
binlog 记录主库所有变更,格式为逻辑日志;relay log 是从库对主库 binlog 的本地副本,内容基本一致,但由从库 I/O 线程写入、SQL 线程消费。binlog 用于复制和恢复,relay log 仅用于从库重放。
Q2:relay_log_recovery 的作用是什么?
当从库崩溃重启时,若 relay_log_recovery=ON,从库会丢弃所有未执行的 relay log,重新从 Relay_Master_Log_File 位置向主库请求事件,避免因 relay log 不完整导致的数据不一致。
Q3:如何判断复制中断是 I/O 还是 SQL 线程问题?
看 Slave_IO_Running 和 Slave_SQL_Running。IO 为 No 说明拉取失败,检查网络、主库 binlog、账号;SQL 为 No 说明重放失败,检查 Last_SQL_Error 和 relay log 中的具体事件。
Q4:relay log 会自动删除吗?
默认 relay_log_purge=ON,SQL 线程执行完的 relay log 会被自动清理。若设置为 OFF,需手动清理,否则磁盘会被占满。
六、总结
relay log 是 MySQL 复制链路中的“缓冲带”和“断点记录器”,理解它的写入与消费机制,是排查复制中断的基础。遇到复制问题时,建议按以下顺序排查:
SHOW SLAVE STATUS\G看线程状态和错误信息。- 区分 I/O 与 SQL 线程问题。
- 用
mysqlbinlog解析 relay log 定位具体事件。 - 根据错误码(1032、1062、1146 等)采取跳过、补数据或重建复制。
- 长期优化:开启并行复制、拆分大事务、监控 relay log 空间。
掌握这套方法,无论是面试还是生产故障处理,都能做到心中有数、手中有术。
未经允许不得转载:任鹏个人博客 » MySQL relay log 作用与复制中断排查实战

