
你的网站只有一台数据库。
双 11 当天,流量暴涨 10 倍。所有的查询(SELECT)和写入(INSERT/UPDATE)都挤在这一台机器上。
结果: CPU 100%,磁盘 I/O 打满,数据库卡死,网站 502 Bad Gateway。
更惨的场景:
运维误删了数据库文件,或者服务器硬盘物理损坏。
结果: 数据全丢,公司原地解散。
救世主:
主从复制 。
让一台机器(Master)专门负责写,几台机器(Slave)专门负责读。
哪怕 Master 挂了,Slave 也能立刻顶上去,数据一份都不会少。
1. 核心原理:三个线程的"传话游戏"
主从复制的本质,就是把主库发生的数据变更,在从库上重放 (Replay) 一遍。
这个过程涉及 3 个核心线程 和 2 个关键日志。
第一步:Master 记录"日记" (Binlog)
- 当 Master 执行了写操作(INSERT/UPDATE/DELETE)时,它不仅会修改内存数据,还会把这次操作记录到 Binlog (Binary Log) 中。
- Binlog 是逻辑日志,记录的是"把 ID=1 的名字改成 Alice"这样的事件。
第二步:传输 (IO Thread & Dump Thread)
- Slave 发起请求: Slave 启动一个 I/O 线程 ,连上 Master,说:"请把 Binlog 发给我,我上次读到了
mysql-bin.000001的位置 1024。" - Master 发送数据: Master 启动一个 Binlog Dump 线程,把 Binlog 内容推送给 Slave。
- Slave 接收落盘: Slave 的 I/O 线程收到数据后,并不直接执行,而是先把它写入自己本地的中转站 ------ Relay Log (中继日志)。
第三步:重放 (SQL Thread)
- Slave 启动一个 SQL 线程。
- 它读取 Relay Log 中的事件,将其转换成 SQL 语句,在 Slave 自己的数据库里再执行一遍。
- 结果: Slave 的数据就和 Master 一模一样了。
2. 三种复制模式:速度与安全的博弈
MySQL 提供了不同的复制策略,以应对不同的业务需求。
模式 A:异步复制 (Asynchronous Replication) ------ 默认
- 机制: Master 写完 Binlog,不等 Slave 确认,直接给客户端返回"成功"。
- 优点: 性能最高。Master 不需要等待网络延迟。
- 缺点: 数据不安全。如果 Master 刚写完 Binlog 就宕机了,而 Binlog 还没传给 Slave,这部分数据就永久丢失了。
模式 B:半同步复制 (Semi-Synchronous Replication)
- 机制: Master 写完 Binlog 后,必须等待至少一个 Slave 收到 Binlog 并写入 Relay Log(返回 ACK),才给客户端返回"成功"。
- 优点: 数据基本安全(除非 Master 和那个 Slave 同时挂)。
- 缺点: 性能有损耗(也就是多了一个 RTT 网络往返时间)。如果超时(默认 10秒),它会退化成异步复制。
模式 C:组复制 (MGR - MySQL Group Replication)
- 机制: 基于 Paxos 协议。多个节点组成一个组,写入操作必须经过大多数节点同意才能提交。
- 优点: 强一致性,自动故障转移,真正的多主架构。
- 缺点: 配置复杂,对网络要求极高。
3. 实战痛点:主从延迟 (Replication Lag)
这是主从架构最大的敌人。
现象:
用户刚注册成功(写入 Master),立马跳到登录页(读取 Slave),结果提示"账号不存在"。
原因:
- 单线程瓶颈: 在 MySQL 5.6 之前,Slave 的 SQL 线程是单线程的。如果 Master 并发很高(比如 1000 TPS),Slave 只能一个个排队执行,根本追不上。
- 大事务: Master 执行了一个
DELETE语句删了 100 万行数据,耗时 10 秒。Slave 重放这个事务也要 10 秒,这就导致了 10 秒的延迟。 - 网络延迟: 跨机房同步。
解决方案:
- 并行复制 (MTS - Multi-Threaded Slave):
- MySQL 5.7+ 引入了基于逻辑时钟 (Logical Clock) 的并行复制。
- 原理: 如果两个事务在 Master 上是并行提交的(说明它们没有锁冲突),那么在 Slave 上也可以并行重放。
- 这让 Slave 的回放速度提升了 10 倍以上。
- 读写分离策略优化:
- 关键业务(如支付、注册后登录)强制读主库。
- 非关键业务(如查看商品列表)读从库。
4. 架构进阶:GTID (Global Transaction ID)
在老版本的 MySQL 中,主从切换是非常痛苦的。你需要手动找 Binlog 文件名和 Position 位置(如 mysql-bin.00005, pos=890)。一旦找错,数据就乱了。
GTID (全局事务 ID) 彻底解决了这个问题。
- 定义: 每个事务都有一个全局唯一的 ID(如
UUID:TransactionId)。 - 机制: Slave 不再告诉 Master "我读到了哪个文件的哪一行",而是直接说 "我已经执行了 1-100 号事务,请把 101 号之后的发给我"。
- 收益: 极大地简化了故障切换(Failover)和搭建从库的流程。
5. 总结
主从复制 是高可用架构的基石。
- 它是备份: 每一台 Slave 都是一份完整的数据副本。
- 它是性能: 通过读写分离,让 1 台 Master 扛写,N 台 Slave 扛读,吞吐量线性增长。
- 它是容灾: Master 挂了,通过 HA 工具(如 Orchestrator, MHA)把 Slave 提升为新 Master,业务秒级恢复。