MySQL 主从同步是如何实现的?
关键词:binlog、I/O 线程、SQL 线程、relay log、GTID、半同步复制。
目标:搞清楚“主库做了什么,从库做了什么,中间又传了什么”。
一、先用一张逻辑图概括一下
逻辑流程可以概括成 4 步:
应用 -> 写主库
主库 -> 写 binlog
从库 -> 拉取主库 binlog(I/O 线程)
从库 -> 回放 relay log(SQL 线程)
更具体一点:
- 主库接收写请求,执行事务,把变更写入 binlog;
- 从库的 I/O 线程从主库拉取 binlog,写到自己的 relay log(中继日志);
- 从库的 SQL 线程读取 relay log,在从库重放这些变更;
- 从而保证主从之间数据尽量一致(有复制延迟)。
二、主从复制的核心:binlog
2.1 binlog 是什么?
binlog(二进制日志) 是 MySQL Server 层的日志,记录“数据变更的逻辑事件”,比如:
INSERT ...UPDATE ...DELETE ...ALTER TABLE ...
作用:
- 主从复制:从库通过读取主库的 binlog 来重放变更;
- 数据恢复:配合全量备份,用 binlog 回放增量数据;
- 审计/数据同步:一些中间件也会基于 binlog 做数据同步。
2.2 binlog 的格式(Statement / Row / Mixed)
binlog 有 3 种格式:
-
STATEMENT(基于语句)
- 记录执行的 SQL 语句本身;
- 优点:日志体积小;
- 缺点:某些不确定性语句可能导致主从执行结果不一致(如
NOW()、RAND()等)。
-
ROW(基于行)
- 记录每一行数据变更前后的值;
- 优点:复制更精确,不会受函数、副作用影响;
- 缺点:日志量大。
-
MIXED(混合)
- MySQL 自动在 STATEMENT 和 ROW 之间选择;
- 一般不确定是否安全时,采用 ROW。
生产环境中:
- 很多场景会选择 ROW 格式,更安全;
- 日志量问题可以用压缩、拆分等方式处理。
三、主从复制的基本流程(经典异步复制)
3.1 主库端:写 binlog
当你在主库执行一个事务:
BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;
内部流程大致是:
- InnoDB 写 undo log / redo log,完成事务更新;
- MySQL Server 层生成对应的 binlog 事件(根据 binlog_format 格式);
- 事务提交时,redo log + binlog 两阶段提交,确保:
- 事务成功提交 ⇒ binlog 一定写成功;
- 防止主从之间出现“主库有数据但 binlog 丢了”的情况。
3.2 从库端:I/O 线程拉 binlog
在从库上配置:
CHANGE MASTER TO
MASTER_HOST = '主库IP',
MASTER_PORT = 3306,
MASTER_USER = 'repl_user',
MASTER_PASSWORD = 'repl_pwd',
MASTER_LOG_FILE = 'mysql-bin.000001',
MASTER_LOG_POS = 4;
START SLAVE;
从库会启动两个线程:
-
I/O 线程
- 连接到主库,发起复制请求;
- 主库为其开启一个 binlog dump 线程;
- 主库将后续 binlog 事件源源不断发给从库;
- 从库 I/O 线程接收后,将其顺序写入本地的 relay log(中继日志)。
-
SQL 线程
- 从 relay log 中依次读取事件;
- 将其“回放”到从库上(等价于在从库执行同样的变更);
最终效果:
- 主库执行完的事务,经过 binlog 流转到从库;
- 从库重放这些事务,数据达到“最终一致”(存在时间延迟)。
3.3 relay log(中继日志)
- 从库本地维护的一个日志文件;
- 结构类似于主库的 binlog;
- 优点:
- I/O 线程和 SQL 线程解耦;
- 即使主库短暂不可用,已有的 relay log 仍可继续重放。
四、复制模式:异步 / 半同步 / 全同步
4.1 异步复制(默认)
- 主库提交事务后:
- 不关心从库有没有同步成功;
- 只要本地事务和 binlog 写成功就算成功。
优点:
- 延迟低,性能好;
- 对主库的压力小。
缺点:
- 如果主库故障,而从库尚未完全同步:
- 可能丢失部分已经“对外提交”的事务;
- 也就是“主库事务提交成功,但从库没有”。
4.2 半同步复制(Semi-Synchronous Replication)
- 需要在主库开启插件或配置:
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_slave_enabled = 1
半同步大致逻辑:
- 主库在事务提交时:
- 必须等至少一个从库确认已收到该事务的 binlog;
- 才向客户端返回“提交成功”;
- 如果等不到从库确认,会自动退回异步模式。
优点:
- 降低了“主库提交成功但 binlog 未到从库”的风险;
- 在主从切换时数据更安全。
缺点:
- 提交延迟会略有增加(需要等待从库 ack);
- 如果网络抖动或从库压力大,会影响主库提交时延。
4.3 全同步复制(强一致,实际很少用)
- 要求所有从库都确认收到并应用该事务后才算提交成功;
- 对性能和可用性影响非常大:
- 任一从库慢/挂,都会拖累整体;
- 很少在 MySQL 生产直接这样玩,一般通过分布式协议(如 Paxos/Raft)框架上实现强一致。
五、主从复制中的位置标识:File/Pos 与 GTID
5.1 传统方式:binlog 文件名 + 偏移量(File/Pos)
MASTER_LOG_FILE:binlog 文件名;MASTER_LOG_POS:在该文件中的偏移量。
问题:
- 切换主库或发生主从链路变更时:
- 需要手工管理 file/pos;
- 容易出错。
5.2 GTID(Global Transaction ID,全局事务 ID)
GTID 形式一般是:
server_uuid:transaction_id
特点:
- 每个事务一个全球唯一的 ID;
- 从库可以根据 GTID 判断哪些事务已经执行,哪些还没有;
- 主从切换时:
- 从节点不再用 file/pos 来定位复制位置;
- 而是根据 GTID 集合自动“对齐”。
开启 GTID 的配置示例(MySQL 5.7+):
gtid_mode = ON
enforce_gtid_consistency = ON
log_slave_updates = ON
优点:
- 简化主从切换、容灾、级联复制;
- 真·按事务维度追踪复制状态。
六、主从架构在业务中的常见用法
6.1 读写分离
典型架构:
- 主库负责写(INSERT/UPDATE/DELETE);
- 从库负责读(SELECT);
- 通过中间件或应用层路由:
- 写请求 → 主库;
- 读请求 → 多个从库做负载均衡。
好处:
- 分担主库读压力;
- 提升整体吞吐。
注意:
- 存在复制延迟:
- 写完立即读,若读走从库,可能读到旧数据;
- 对“强一致读”的请求可以强制走主库。
6.2 高可用与故障切换
常见模式:
- 一主多从 + 判断主库健康;
- 主库挂了时,从库中选一个提升为新主库;
- 其他从库指向新主库继续复制。
依赖:
- 心跳检测(MHA、Orchestrator 等工具);
- GTID 能显著简化切换过程。
七、主从复制的延迟与一致性问题
7.1 复制延迟的原因
- 从库性能较差(CPU、磁盘、IO)导致 SQL 线程重放慢;
- 从库执行了复杂查询,占用大量资源;
- 网络延迟或带宽限制;
- 主库写入量突增。
7.2 应对策略
- 提升从库硬件、参数调优;
- 避免在从库上执行超重查询或跑大报表;
- 使用多从库分担读压力;
- 对于需要强一致读的场景(例如刚写完马上要读):
- 优先路由到主库;
- 或采用“读写都在主库” + 从库主要做备份/降级用途。
八、主从复制的配置步骤(简要版)
以经典非 GTID 异步复制为例:
-
主库开启 binlog
[mysqld] server-id = 1 log-bin = mysql-bin binlog_format = ROW -
创建复制用户(在主库)
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_pwd'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES; -
从库配置 server-id
[mysqld] server-id = 2 relay-log = relay-bin -
在从库上指定主库信息并开启复制
CHANGE MASTER TO MASTER_HOST = '主库IP', MASTER_USER = 'repl', MASTER_PASSWORD = 'repl_pwd', MASTER_LOG_FILE = 'mysql-bin.000001', MASTER_LOG_POS = 4; START SLAVE; -
检查复制状态
SHOW SLAVE STATUS\G;关注:
Slave_IO_Running: YesSlave_SQL_Running: Yes- 延迟相关字段。
GTID 模式下配置稍有不同,但原理类似。
九、总结
-
核心机制:
- 主库写 binlog;
- 从库 I/O 线程从主库拉 binlog 写入 relay log;
- 从库 SQL 线程从 relay log 中重放事件。
-
复制模式:
- 默认是异步复制(主库不等从库);
- 可配置半同步复制提高数据安全;
- 理论上的全同步复制通常不用。
-
位置识别:
- 传统:binlog 文件名 + pos;
- 现代:GTID,按事务 ID 维度管理复制。
-
典型用法:
- 读写分离(主写从读);
- 高可用 + 故障切换(主挂从顶上)。
-
问题与处理:
- 复制延迟不可避免,只能尽量优化;
- 对强一致读:写后读走主库;
- 监控
SHOW SLAVE STATUS,确保复制线程健康。
理解了“主库写 binlog → 从库拉 binlog → 重放到自身”这条链路,再加上对异步/半同步、GTID 的认识,你基本就把 MySQL 主从同步的底层逻辑吃透了。
622

被折叠的 条评论
为什么被折叠?



