MySQL主从同步原理

MySQL 主从同步是如何实现的?

关键词:binlog、I/O 线程、SQL 线程、relay log、GTID、半同步复制。
目标:搞清楚“主库做了什么,从库做了什么,中间又传了什么”。


一、先用一张逻辑图概括一下

逻辑流程可以概括成 4 步:

应用 -> 写主库
主库 -> 写 binlog
从库 -> 拉取主库 binlog(I/O 线程)
从库 -> 回放 relay log(SQL 线程)

更具体一点:

  1. 主库接收写请求,执行事务,把变更写入 binlog
  2. 从库的 I/O 线程从主库拉取 binlog,写到自己的 relay log(中继日志);
  3. 从库的 SQL 线程读取 relay log,在从库重放这些变更
  4. 从而保证主从之间数据尽量一致(有复制延迟)。

二、主从复制的核心:binlog

2.1 binlog 是什么?

binlog(二进制日志) 是 MySQL Server 层的日志,记录“数据变更的逻辑事件”,比如:

  • INSERT ...
  • UPDATE ...
  • DELETE ...
  • ALTER TABLE ...

作用:

  1. 主从复制:从库通过读取主库的 binlog 来重放变更;
  2. 数据恢复:配合全量备份,用 binlog 回放增量数据;
  3. 审计/数据同步:一些中间件也会基于 binlog 做数据同步。

2.2 binlog 的格式(Statement / Row / Mixed)

binlog 有 3 种格式:

  1. STATEMENT(基于语句)

    • 记录执行的 SQL 语句本身;
    • 优点:日志体积小;
    • 缺点:某些不确定性语句可能导致主从执行结果不一致(如 NOW()RAND() 等)。
  2. ROW(基于行)

    • 记录每一行数据变更前后的值;
    • 优点:复制更精确,不会受函数、副作用影响;
    • 缺点:日志量大。
  3. 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;

内部流程大致是:

  1. InnoDB 写 undo log / redo log,完成事务更新;
  2. MySQL Server 层生成对应的 binlog 事件(根据 binlog_format 格式);
  3. 事务提交时,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;

从库会启动两个线程:

  1. I/O 线程

    • 连接到主库,发起复制请求;
    • 主库为其开启一个 binlog dump 线程
    • 主库将后续 binlog 事件源源不断发给从库;
    • 从库 I/O 线程接收后,将其顺序写入本地的 relay log(中继日志)
  2. 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 异步复制为例:

  1. 主库开启 binlog

    [mysqld]
    server-id = 1
    log-bin = mysql-bin
    binlog_format = ROW
    
  2. 创建复制用户(在主库)

    CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_pwd';
    GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
    FLUSH PRIVILEGES;
    
  3. 从库配置 server-id

    [mysqld]
    server-id = 2
    relay-log = relay-bin
    
  4. 在从库上指定主库信息并开启复制

    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;
    
  5. 检查复制状态

    SHOW SLAVE STATUS\G;
    

    关注:

    • Slave_IO_Running: Yes
    • Slave_SQL_Running: Yes
    • 延迟相关字段。

GTID 模式下配置稍有不同,但原理类似。


九、总结

  1. 核心机制

    • 主库写 binlog
    • 从库 I/O 线程从主库拉 binlog 写入 relay log
    • 从库 SQL 线程从 relay log 中重放事件。
  2. 复制模式

    • 默认是异步复制(主库不等从库);
    • 可配置半同步复制提高数据安全;
    • 理论上的全同步复制通常不用。
  3. 位置识别

    • 传统:binlog 文件名 + pos;
    • 现代:GTID,按事务 ID 维度管理复制。
  4. 典型用法

    • 读写分离(主写从读);
    • 高可用 + 故障切换(主挂从顶上)。
  5. 问题与处理

    • 复制延迟不可避免,只能尽量优化;
    • 对强一致读:写后读走主库;
    • 监控 SHOW SLAVE STATUS,确保复制线程健康。

理解了“主库写 binlog → 从库拉 binlog → 重放到自身”这条链路,再加上对异步/半同步、GTID 的认识,你基本就把 MySQL 主从同步的底层逻辑吃透了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值