返回首页

21|主从复制原理

适用版本:MySQL 8.0.x

MySQL 主从复制,是数据库架构里最经典、也最常见的能力之一。无论是读写分离、备库容灾、数据分析订阅,还是高可用切换,背后几乎都离不开复制。

但“会搭主从”和“理解主从”是两回事。很多线上问题,例如:

  • 为什么从库延迟越来越大?
  • 为什么切换后数据不一致?
  • 为什么大事务会把复制链路拖慢?
  • GTID 到底解决了什么问题?

如果只停留在“主库写、从库跟着同步”的印象层面,很难真正定位问题。

这篇文章会按照教程/学习笔记的方式,系统讲清楚 MySQL 8.0 中主从复制的原理、关键角色、工程实践与常见坑点。

说明:MySQL 8.0 在文档中更推荐使用 source / replica 术语,但很多历史命令、习惯表达里仍会看到 master / slave。本文为便于学习,标题保留“主从复制”,正文会尽量统一为“主库 / 从库”。


一、主从复制到底解决什么问题

先不要急着背线程名,先看它的工程价值。

主从复制常见用途包括:

  1. 读写分离:主库负责写,从库承担部分读取压力。
  2. 高可用与容灾:主库故障时,可以切换到从库继续服务。
  3. 备份隔离:把备份、校验、分析任务放到从库,减少对主库影响。
  4. 数据分发:让下游系统订阅主库数据变更。

如果一句话概括:

主从复制的本质,是把主库上的数据变更,按顺序传递到从库并重放,从而让从库逼近主库状态。

注意这个定义里有两个关键词:

  • 按顺序传递
  • 重放变更

它意味着复制从来不是“复制磁盘文件”,而是“复制变更过程”。


二、复制依赖什么基础能力

MySQL 主从复制的基础,是 binlog

1. 主库必须开启 binlog

因为主库要把事务变更写入 binlog,复制链路才能把这些事件发给从库。

常见前提包括:

  • log_bin = ON
  • 有稳定的 server_id
  • 从库有权限访问主库复制账号

2. 从库不是直接读主库数据页

从库拿到的不是 InnoDB 数据页,而是主库产生的 binlog 事件。

然后从库再把这些事件:

  • 先落到 relay log(中继日志)
  • 再由回放线程执行

所以你要始终记住:

复制链路是围绕 binlog / relay log 建立的,不是围绕表文件直接同步的。


三、主从复制的核心角色

学习复制时,最常见的三个角色一定要分清。

1. 主库上的 binlog

主库每次事务提交后,会把变更写入 binlog。复制的“源头”就是它。

2. 从库上的 I/O 线程

从库会连接主库,请求从某个 binlog 文件和位置开始拉取事件。

拉到之后,写入本地的 relay log

3. 从库上的 SQL 线程 / applier 线程

从库读取 relay log 中的事件,并在本地执行,重放主库上的变更。

所以复制链路的大致流向是:

主库 binlog -> 从库 I/O 线程 -> 从库 relay log -> 从库 SQL/applier 线程 -> 从库数据

这条链一定要记牢,后面排查复制延迟时会频繁用到。


四、一条事务是如何从主库到从库的

下面用一个最典型的例子说明:

UPDATE orders SET status = 2 WHERE id = 1001;

第 1 步:事务在主库提交

主库执行该更新,完成:

  • InnoDB 内部修改
  • redo / undo 处理
  • binlog 写入
  • 两阶段提交保证一致性

到这里,这笔事务已经成为主库 binlog 中的一条已提交事件。

第 2 步:从库 I/O 线程拉取 binlog

从库会告诉主库:

  • 我当前同步到哪个文件
  • 哪个位点
  • 或者当前 GTID 集合到哪里

主库就把后续 binlog 事件发给从库。

第 3 步:从库写 relay log

从库不会直接边收边执行,而是先把收到的事件写入本地 relay log。

这样做的好处:

  • 拉取与执行解耦
  • 即使执行变慢,拉取也可以先持续推进一部分
  • 出问题时,relay log 可以作为本地重放依据

第 4 步:从库执行 relay log

从库的 SQL/applier 线程读取 relay log,按顺序执行对应事件,在本地重放同样的数据变更。

完成后,从库数据逐步逼近主库。


五、为什么主从复制通常是异步的

很多业务第一次接触复制,会默认以为主库写成功等于从库也写成功。实际上默认并不是这样。

1. 异步复制的含义

在默认的异步复制中:

  • 主库事务提交成功
  • 不需要等待从库确认已经接收或执行完成
  • 主库即可向应用返回成功

所以:

  • 主库性能更容易做高
  • 但主从之间会天然存在时间差

这就是所谓的 复制延迟

2. 异步复制的风险

如果主库刚提交成功,但从库还未来得及拉取或执行这笔 binlog,此时主库故障:

  • 从库可能缺少最近部分事务
  • 切换后就会出现数据丢失窗口

这也是为什么高可用架构里,不能只会配复制,还要理解复制一致性的边界。


六、半同步复制在解决什么问题

为降低异步复制的丢失窗口,MySQL 还支持 半同步复制(Semi-Synchronous Replication)

1. 半同步的基本思想

主库事务提交后,不是完全不等从库,而是至少等待:

  • 某个从库已经接收到对应 binlog 的确认

然后主库再向客户端返回成功。

2. 它解决了什么

它降低了“主库提交成功但所有从库都还没收到日志”的风险。

3. 它没有解决什么

半同步通常只保证“至少有从库收到日志”,不等于:

  • 从库已经执行完成
  • 应用读从库时一定能马上读到最新值
  • 任何故障切换都绝对零丢失

所以半同步是可靠性增强,不是万能一致性方案。


七、位点复制与 GTID 复制

这是主从复制学习中的一个重要分水岭。

1. 传统位点复制

早期复制主要依赖:

  • binlog 文件名
  • 文件内 position

从库记录“我同步到哪一个文件、哪一个偏移位置”了。

这套方式能工作,但在主从切换、链路重建时操作比较繁琐,也容易出错。

2. GTID 是什么

GTID(Global Transaction Identifier,全局事务 ID)可以理解为给每个事务一个全局唯一编号。

这样从库不必只记“文件 + 位置”,而是可以记:

  • 我已经执行过哪些事务
  • 还缺哪些事务

3. GTID 的工程价值

GTID 最大的好处是:

  • 主从切换更方便
  • 重建复制更清晰
  • 避免手工找位点的复杂度
  • 更适合自动化高可用体系

在 MySQL 8.0 的新部署中,通常更推荐使用 GTID 复制。


八、从库延迟到底是怎么产生的

这是线上最常见的问题之一。

1. 拉取慢

如果主从网络不稳定、主库发送压力大、从库 I/O 线程状态异常,可能导致:

  • 主库 binlog 产生得快
  • 从库拉取得慢

于是 relay log 追不上。

2. 执行慢

更常见的是:

  • relay log 已经拉下来不少
  • 但 SQL/applier 线程执行不过来

原因可能包括:

  • 大事务
  • 缺索引导致从库执行慢
  • 从库机器资源不足
  • 从库还承担大量查询
  • DDL 阻塞

3. 单线程瓶颈

历史上复制 SQL 线程单线程执行是延迟的重要原因之一。MySQL 8.0 已支持更成熟的并行复制能力,但并不意味着所有场景都天然无延迟。

4. 大事务特别危险

一个大事务会导致:

  • 主库生成巨大 binlog
  • 从库应用耗时很长
  • 在事务提交完成前,后续事务可能难以前进

所以大事务是复制延迟的典型放大器。


九、并行复制为什么重要

1. 单线程复制的局限

如果从库只能一个事务一个事务串行执行,那么主库并发越高,从库越容易落后。

2. 并行复制的基本思路

MySQL 8.0 可以根据事务依赖关系,把部分彼此独立的事务并行回放。

这样带来的收益是:

  • 更好利用多核 CPU
  • 缩短从库追赶时间
  • 降低热点不强场景下的复制延迟

3. 并行不是无限并行

如果事务之间强依赖、都更新同一批热点数据,那么并行度天然有限。

所以并行复制是能力增强,不是银弹。


十、主从复制中的一致性边界

理解主从复制,最容易忽略的一点是:

从库不保证永远和主库实时一致。

1. 读写分离下的典型问题

应用执行:

  1. 在主库写入一条数据
  2. 立刻去从库查询

如果此时复制尚未完成,从库可能查不到最新结果。

这就是典型的 读到旧数据 问题。

2. 常见应对策略

工程上常见做法包括:

  • 写后立即读走主库
  • 关键链路关闭读写分离
  • 基于业务 token 做“读主若干秒”
  • 结合延迟监控进行路由降级

数据库复制只是基础,最终一致性的体验还要靠应用架构配合。


十一、复制相关的关键文件与日志

1. binlog

在主库上,记录事务变更事件,是复制的源头。

2. relay log

在从库上,保存从主库拉取来的事件,相当于从库本地的“待执行中继站”。

3. applier 执行状态

从库会维护自己执行到哪里、已完成哪些事务等元信息。

如果你理解了这三层,就能更容易定位“卡在拉取还是卡在执行”。


十二、常用命令与排查入口

1. 查看主库 binlog 状态

SHOW MASTER STATUS;

可以看到当前 binlog 文件和位置。

2. 查看从库复制状态

SHOW REPLICA STATUS\G

历史上也常见:

SHOW SLAVE STATUS\G

重点关注字段通常包括:

  • I/O 线程是否正常
  • SQL 线程是否正常
  • Seconds_Behind_Source
  • 当前 relay log / 位点信息
  • 最近错误信息

3. 查看 GTID 相关参数

SHOW VARIABLES LIKE 'gtid_mode';
SHOW VARIABLES LIKE 'enforce_gtid_consistency';

4. 查看 binlog 配置

SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';

十三、主从复制中的常见故障场景

1. 主从延迟持续升高

优先排查:

  • 主库是否有大事务
  • 从库执行是否缺索引
  • 从库资源是否不足
  • 是否有慢 SQL 或 DDL 阻塞
  • 并行复制是否开启且配置合理

2. 复制中断

可能原因包括:

  • 主从表结构不一致
  • 从库执行报错
  • 唯一键冲突
  • 人工误操作修改了从库数据
  • 网络或权限异常

3. 切换后数据缺失

往往与以下因素相关:

  • 异步复制导致最后一段事务未同步
  • 错误选择了延迟较大的从库做提升
  • 切换前未校验复制追平状态

4. 从库越跑越慢

从库不是“只负责复制就一定轻松”。如果它还承担:

  • 复杂报表查询
  • 备份任务
  • 大量只读流量

这些都可能与复制线程争抢资源,导致延迟扩大。


十四、工程实践建议

1. 新系统优先使用 GTID

原因很实际:

  • 切换方便
  • 自动化友好
  • 减少人为定位位点出错概率

2. 大事务拆分

复制最怕大事务。无论是批量更新、删除还是导入,都建议:

  • 按主键范围分批
  • 控制单事务大小
  • 观察 binlog 增长与复制延迟

3. 从库不要承载失控查询

如果从库既要复制,又要跑很多慢分析 SQL,很容易造成 applier 线程资源不足。

4. 监控不要只看一个延迟指标

除了 Seconds_Behind_Source,还应结合观察:

  • I/O 线程状态
  • SQL 线程状态
  • relay log 堆积量
  • 主库 binlog 生成速率
  • 从库 CPU / 磁盘 / IO wait

5. 切换前先确认复制追平

不要看到主库有故障就立刻随便提升一个从库。至少要先确认:

  • 该从库是否正常接收和执行
  • 是否存在明显延迟
  • 是否有复制错误
  • 最后事务是否追平

十五、一个完整的复制认知框架

读到这里,你应该能把主从复制理解成下面这条链:

  1. 主库事务提交
  2. 主库写 binlog
  3. 从库 I/O 线程拉取 binlog
  4. 从库写 relay log
  5. 从库 SQL/applier 线程重放 relay log
  6. 从库逐步逼近主库状态
  7. 在异步/半同步、位点/GTID、串行/并行复制这些机制影响下,形成不同的一致性与性能表现

这个框架比记几个线程名更重要,因为它能直接指导排障和架构决策。


十六、小结

MySQL 主从复制不是一个“配好就不用管”的功能,而是一条持续运行的数据变更传输链路。

你至少应该记住以下几点:

  1. 复制的基础是 binlog。
  2. 从库通过 I/O 线程拉取 binlog,写入 relay log,再由 SQL/applier 线程执行。
  3. 默认异步复制存在延迟与故障切换丢失窗口。
  4. GTID 更适合现代 MySQL 8.0 的自动化运维场景。
  5. 大事务、从库资源不足、慢查询与表结构问题,都是复制延迟的高频根因。

当你以后再看主从延迟、读写分离一致性、故障切换这些话题时,就不会把它们视作分散问题,而能回到同一条复制链路上统一理解。


📝 版权声明:本文为原创技术博客,转载请注明出处。

如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!

上一篇

20|binlog 与两阶段提交

下一篇

22|MySQL 备份与恢复