← 返回题目列表

MySQL 主从复制的原理是什么?

高频 中等 第 12 / 28 题 更新于 2026/07/27
MySQL主从复制binlog复制延迟

简化版

MySQL 主从复制的核心是:主库把变更写入 binlog,从库拉取 binlog 写入中继日志,再由 SQL 线程或复制执行线程重放这些变更。它常用于读写分离、备份和容灾,但天然可能存在复制延迟。

详细版

典型复制流程:

  1. 主库提交事务并写入 binlog;
  2. 从库 I/O 线程连接主库,请求 binlog;
  3. 主库发送 binlog 事件给从库;
  4. 从库写入 relay log;
  5. 从库 SQL 线程或复制执行线程读取 relay log 并执行。

常见问题:

  • 复制延迟:主库写入成功后,从库还没重放完成,读从库可能读到旧数据。
  • 主从不一致:非确定性 SQL、手工改从库、复制中断等都可能导致。
  • 故障切换复杂:主库故障后,需要保证新主库数据尽量完整,并处理应用连接切换。

复制可以是异步、半同步或组复制等模式。普通异步复制性能好,但不能保证从库实时拿到所有事务。

完整版教学

一、binlog 是复制的基础

主从复制不是把数据页直接拷贝过去,而是基于 binlog 传播变更。主库执行写操作后,把逻辑变更记录到 binlog。从库拿到这些事件后,在自己本地重放,从而让数据逐渐追上主库。

这也解释了为什么 binlog 格式、事务提交顺序、复制位点都很重要。复制同步的是“变更历史”,不是简单的文件镜像。

binlog 常见格式有 statement、row、mixed。现代生产里更常见 row 格式,因为它记录行级变更结果,对非确定性函数、触发器影响等情况更稳。比如 update account set balance = balance - 100 where id = 1,row 格式会记录具体哪行变成什么值,从库按事件重放,结果更可控。

binlog 格式记录内容特点
statement原始 SQL日志小,但非确定性 SQL 风险高
row行变更前后信息更可靠,日志可能更大
mixed两者混合MySQL 根据场景选择

二、复制链路怎么跑起来

从库一般有两个关键动作:

  • 拉取主库 binlog,写入本地 relay log;
  • 读取 relay log,并在从库执行对应事件。

旧版本资料常说 I/O 线程和 SQL 线程。现代 MySQL 支持多线程复制,执行层可以并行重放部分事务,但原理仍然是拉取日志、保存日志、重放日志。

可以把复制链路拆成三段:主库产生 binlog,从库接收并写 relay log,从库执行 relay log。任何一段慢下来都会造成延迟。面试回答时用“拉取、落中继日志、重放”这三个动词,比只说“主库同步给从库”更准确。

Master:
事务提交 -> 写 binlog -> dump 线程发送事件

Replica:
I/O 接收线程 -> 写 relay log -> SQL/worker 线程重放

记忆钩子:主从复制不是从库直接读主库数据页,而是从库消费主库的 binlog 变更流。

三、为什么会有主从延迟

主从延迟的根源是:主库提交完成,不等于从库已经执行完成。延迟可能来自:

  • 主库写入压力太大,binlog 产生速度超过从库重放速度;
  • 从库机器性能较弱;
  • 大事务执行时间长;
  • SQL 单线程或并行度不足;
  • 网络抖动;
  • 从库上还有额外查询压力。

读写分离场景下,如果写完马上读从库,就可能读到旧数据。关键业务可以读主库,或者使用延迟检测、会话一致性策略。

用数字看:主库每秒产生 5000 个事务,从库每秒只能重放 3500 个事务,每秒就积压 1500 个事务;持续 60 秒就积压 9 万个事务。即使网络没有问题,从库也会越来越落后。大事务尤其明显,一个事务更新 100 万行,主库提交后从库必须重放很久,期间延迟可能陡增。

业务上最典型的坑是“写后读”。用户刚修改昵称,应用马上把下一次读取路由到从库,如果从库还没重放这条 binlog,页面就显示旧昵称。解决方式可以是写后短时间读主库、按 GTID/位点等待从库追上、或对关键接口禁用读从库。

四、异步复制和半同步复制的区别

异步复制下,主库事务提交不需要等待从库确认。它吞吐好、延迟低,但主库刚提交就宕机时,从库可能还没收到这部分 binlog。

半同步复制会要求至少一个从库确认收到事务相关日志后,主库再向客户端返回成功。它能降低数据丢失风险,但会增加提交延迟。注意,半同步通常强调“收到日志”,不等于从库已经执行完查询可见。

对比可以这样说:

模式主库提交是否等从库优点风险
异步复制不等性能好、延迟低主库故障可能丢最后一段已提交事务
半同步复制至少等一个确认收到日志降低数据丢失风险提交链路变长,仍可能有查询延迟
组复制多节点协议保证更强一致性高可用能力更强架构和运维复杂度更高

半同步里“确认收到”不等于“已经执行”。所以它主要降低主库宕机导致事务丢失的风险,不直接保证读从库一定读到最新值。

五、如何降低复制风险

常见做法包括:

  • 避免大事务,把批量写拆小;
  • 从库配置合理并行复制;
  • 监控复制延迟和复制错误;
  • 读写分离时关键读走主库;
  • 从库只读,避免人为写入造成不一致;
  • 使用 GTID 简化故障切换和位点管理。

还要避免在从库执行业务写入。主从复制默认假设从库通过重放主库 binlog 变更数据,如果人为在从库改数据,就可能造成主从不一致甚至复制中断。生产中通常设置 read_onlysuper_read_only,并限制普通账号写权限。

六、故障切换为什么不只是改连接地址

主库宕机后,选择哪个从库提升为新主库,要看它是否拥有最完整的数据。如果从库 A 延迟 1 秒,从库 B 延迟 20 秒,把 B 提升为主库可能丢更多事务。使用 GTID 后,可以更方便地判断事务集合和补齐缺失事务,但仍需要成熟的切换流程。

故障切换还涉及应用连接、旧主库恢复后的角色、复制拓扑重建、双写风险防护。面试回答主从复制时,提到“复制不等于强一致高可用,切主需要处理延迟和数据完整性”,会比只背线程模型更工程化。

七、常见误区与追问

  • 误区:主从复制是把主库数据文件直接复制给从库。 MySQL 复制核心是 binlog 事件传播和从库重放,不是简单拷贝数据页。
  • 误区:半同步复制能保证从库马上可读到最新数据。 半同步通常保证至少一个从库收到日志确认,不等于从库已经执行完成。
  • 误区:读写分离后所有读都可以走从库。 写后立刻读、支付状态、权限变更等关键读应考虑读主库或等待从库追上。
  • 误区:主从延迟只由网络导致。 大事务、从库性能、并行复制不足、从库查询压力和主库写入峰值都可能导致延迟。
  • 追问:GTID 的价值是什么? GTID 给每个事务全局标识,能简化复制位点管理、主从切换和判断事务是否已经执行。
  • 追问:如何降低主从不一致风险? 使用 row 格式、从库只读、监控复制错误和延迟、避免非确定性写法,并建立规范的故障切换流程。

八、加强记忆

MySQL 主从复制的主线是:主库写 binlog,从库拉取并写 relay log,再由执行线程重放变更。异步复制性能好但可能丢最后一段事务,半同步降低丢失风险但增加提交等待,而且不代表从库已经执行可见。读写分离最容易踩写后读旧数据的坑,所以关键读要读主、等待位点或做会话一致性;故障切换也要先确认哪个从库数据最完整。