主从复制原理

面试官问:"MySQL 主从复制是怎么实现的?"

小张说:"主库写入,从库读取。"

面试官追问:"主库写入后,数据是怎么同步到从库的?"

小张说:"...用 binlog?"

面试官继续追问:"binlog 格式有哪几种?主从复制有几种方式?"

小张开始支支吾吾。

主从复制是 MySQL 高可用的基石。这道题考的是候选人对 MySQL 主从架构的理解深度。能说清楚 binlog 格式和三种复制方式的候选人,对 MySQL 的理解已经相当系统。

一、主从复制架构 🔴

1.1 复制架构图

┌──────────────┐          binlog          ┌──────────────┐
│              │ ─────────────────────────→ │              │
│    Master     │                           │    Slave     │
│              │                           │              │
│  ┌────────┐ │                           │  ┌────────┐  │
│  │ binlog │ │ ← 写入新数据时记录         │  │ relay  │  │
│  └────────┘ │                           │  │  log   │  │
└──────────────┘                           │  └────────┘  │
                                            │      ↓      │
                                            │  ┌────────┐  │
                                            │  │ SQL    │  │
                                            │  │ thread │  │
                                            │  └────────┘  │
                                            └──────────────┘

核心流程

  1. Master:主库写入数据,同时记录 binlog
  2. Dump 线程:Master 的 Dump 线程发送 binlog 给 Slave
  3. IO 线程:Slave 的 IO 线程接收 binlog,写入 relay log
  4. SQL 线程:Slave 的 SQL 线程读取 relay log,执行 SQL

1.2 主从复制流程

-- Step 1: 主库写入
INSERT INTO orders VALUES (...);

-- Step 2: 主库记录 binlog
binlog 写入记录:[Table: orders, Type: INSERT, Data: ...]

-- Step 3: Dump 线程发送 binlog
Master: Dump thread → 发送 binlog events → Slave

-- Step 4: 从库 IO 线程接收
Slave: IO thread → 接收 binlog events → 写入 relay-log

-- Step 5: 从库 SQL 线程重放
Slave: SQL thread → 读取 relay-log → 执行 INSERT → 数据同步

1.3 ❌ 错误示范

候选人原话:"主从复制是同步的,主库写入后从库立即同步。"

问题诊断:MySQL 默认是异步复制。主库写入后不等待从库确认就返回成功。只有半同步复制或全同步复制才保证从库同步。

候选人原话 2:"从库也可以写入数据。"

问题诊断:默认情况下从库是只读的(read_only=ON)。如果从库写入,主从数据会不一致。

【面试官心理】 这道题我能从基础追问到生产选型。比如我会问:"异步复制、半同步复制、全同步复制各有什么优缺点?"能权衡性能和一致性的候选人是 P6+ 水平。

二、binlog 日志格式 🔴

2.1 三种 binlog 格式

格式说明优点缺点
STATEMENT记录 SQL 语句binlog 小,可审计函数/存储过程可能不一致
ROW记录行级别的变更精确,可靠binlog 大
MIXED混合模式,自动选择平衡复杂

2.2 STATEMENT 格式

-- Master: 执行 SQL
UPDATE orders SET amount = amount + 100 WHERE user_id = 1;

-- binlog 记录:
UPDATE orders WHERE user_id = 1;
-- (记录的是 SQL,不是行变更)

-- Slave: 重放 SQL
UPDATE orders SET amount = amount + 100 WHERE user_id = 1;

问题:如果 SQL 中使用了 NOW()RAND() 等非确定性函数,Master 和 Slave 执行结果可能不一致。

2.3 ROW 格式

-- Master: 执行 SQL
UPDATE orders SET amount = amount + 100 WHERE user_id = 1;

-- binlog 记录:
UPDATE orders SET amount=1100 WHERE id=1 AND amount=1000;
-- (记录每行的具体变更)

-- Slave: 重放行变更
UPDATE orders SET amount=1100 WHERE id=1 AND amount=1000;

优点:精确记录每一行的变更,不受函数/存储过程影响。

缺点:binlog 体积大,特别是在批量更新时。

2.4 MIXED 格式

-- MySQL 自动选择:
-- 普通 SQL 用 STATEMENT 格式
-- 非确定性 SQL(包含 NOW(), RAND() 等)用 ROW 格式

三、复制方式 🟡

3.1 异步复制(默认)

Master →→→→→→→→→→→→→ Slave
  ↓                            ↓
写入成功                   异步接收并重放
立即返回

特点

  • 主库写入后立即返回客户端,不等待从库确认
  • 从库可能有延迟
  • 性能最高,但一致性最低
  • 数据可能丢失:主库宕机时,部分 binlog 可能还没发送到从库

3.2 半同步复制(Semi-sync)

-- 开启半同步复制
-- Master: 安装半同步插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
-- Slave: 安装半同步插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Master →→→→→→→→→→→→→ Slave
  ↓                            ↓
写入成功                   等待至少一个从库确认
等待确认(超时则退化为异步)

特点

  • 主库等待至少一个从库写入 relay log 并返回确认
  • 超时后自动退化为异步复制
  • 比异步复制更安全,性能略低
  • 至少一个从库一致

3.3 全同步复制

Master →→→→→→→→→→→→→ Slave1
  ↓                   ↓
写入成功         等待所有从库确认
等待所有从库确认

特点

  • 主库等待所有从库确认后才返回客户端
  • 性能最差,但一致性最高
  • 适合对数据一致性要求极高的场景(通常搭配集群)

四、GTID 复制 🟡

4.1 GTID 是什么

GTID(Global Transaction Identifier)是事务的全局唯一标识符。

-- GTID 格式:source_id:transaction_id
-- 例如:3E11FA47-71CA-11E1-9E33-C80AA9429562:23

-- 开启 GTID 模式
SET GLOBAL gtid_mode = ON;
SET GLOBAL enforce_gtid_consistency = ON;

4.2 GTID 的优势

特性传统复制GTID 复制
故障转移手动指定 binlog 位置自动定位
延时检测难以检测通过 GTID 轻松识别
数据一致性可能出现 Position 偏移GTID 唯一性保证
切换难度高(需要精确位置)低(基于 GTID)

五、生产避坑 🟢

5.1 主从延迟问题

-- 查看从库延迟
SHOW SLAVE STATUS\G;
-- Seconds_Behind_Master: 从库落后主库的秒数

-- 延迟原因:
-- 1. 从库机器性能差
-- 2. 从库执行 SQL 慢(大事务)
-- 3. 从库配置了太多索引
-- 4. 网络延迟

5.2 主从切换

-- 1. 停止主库写入
SET GLOBAL read_only = ON;
-- 等待所有应用切换

-- 2. 确认从库追上主库
SHOW SLAVE STATUS\G;
-- 确认 Seconds_Behind_Master = 0

-- 3. 提升从库为主库
STOP SLAVE;
RESET SLAVE ALL;
-- 配置其他从库指向新的主库

【面试官心理】 问主从复制的候选人里,能说出 binlog 三种格式的区别和三种复制方式的是大多数。能说清 GTID 复制的优势和切换流程的是少数。P7 候选人应该能说出半同步复制的"等待确认"超时时间设置,以及如何监控主从延迟。


级别考察重点期望回答
P5基础流程binlog、主从复制基本流程
P6格式与方式binlog 三种格式区别、三种复制方式
P7深度运维GTID 复制、主从切换、延迟监控