适用版本:MySQL 8.0.x
MySQL 主从复制,是数据库架构里最经典、也最常见的能力之一。无论是读写分离、备库容灾、数据分析订阅,还是高可用切换,背后几乎都离不开复制。
但“会搭主从”和“理解主从”是两回事。很多线上问题,例如:
- 为什么从库延迟越来越大?
- 为什么切换后数据不一致?
- 为什么大事务会把复制链路拖慢?
- GTID 到底解决了什么问题?
如果只停留在“主库写、从库跟着同步”的印象层面,很难真正定位问题。
这篇文章会按照教程/学习笔记的方式,系统讲清楚 MySQL 8.0 中主从复制的原理、关键角色、工程实践与常见坑点。
说明:MySQL 8.0 在文档中更推荐使用 source / replica 术语,但很多历史命令、习惯表达里仍会看到 master / slave。本文为便于学习,标题保留“主从复制”,正文会尽量统一为“主库 / 从库”。
一、主从复制到底解决什么问题
先不要急着背线程名,先看它的工程价值。
主从复制常见用途包括:
- 读写分离:主库负责写,从库承担部分读取压力。
- 高可用与容灾:主库故障时,可以切换到从库继续服务。
- 备份隔离:把备份、校验、分析任务放到从库,减少对主库影响。
- 数据分发:让下游系统订阅主库数据变更。
如果一句话概括:
主从复制的本质,是把主库上的数据变更,按顺序传递到从库并重放,从而让从库逼近主库状态。
注意这个定义里有两个关键词:
- 按顺序传递
- 重放变更
它意味着复制从来不是“复制磁盘文件”,而是“复制变更过程”。
二、复制依赖什么基础能力
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. 读写分离下的典型问题
应用执行:
- 在主库写入一条数据
- 立刻去从库查询
如果此时复制尚未完成,从库可能查不到最新结果。
这就是典型的 读到旧数据 问题。
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. 切换前先确认复制追平
不要看到主库有故障就立刻随便提升一个从库。至少要先确认:
- 该从库是否正常接收和执行
- 是否存在明显延迟
- 是否有复制错误
- 最后事务是否追平
十五、一个完整的复制认知框架
读到这里,你应该能把主从复制理解成下面这条链:
- 主库事务提交
- 主库写 binlog
- 从库 I/O 线程拉取 binlog
- 从库写 relay log
- 从库 SQL/applier 线程重放 relay log
- 从库逐步逼近主库状态
- 在异步/半同步、位点/GTID、串行/并行复制这些机制影响下,形成不同的一致性与性能表现
这个框架比记几个线程名更重要,因为它能直接指导排障和架构决策。
十六、小结
MySQL 主从复制不是一个“配好就不用管”的功能,而是一条持续运行的数据变更传输链路。
你至少应该记住以下几点:
- 复制的基础是 binlog。
- 从库通过 I/O 线程拉取 binlog,写入 relay log,再由 SQL/applier 线程执行。
- 默认异步复制存在延迟与故障切换丢失窗口。
- GTID 更适合现代 MySQL 8.0 的自动化运维场景。
- 大事务、从库资源不足、慢查询与表结构问题,都是复制延迟的高频根因。
当你以后再看主从延迟、读写分离一致性、故障切换这些话题时,就不会把它们视作分散问题,而能回到同一条复制链路上统一理解。
📝 版权声明:本文为原创技术博客,转载请注明出处。
如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!