核心概念
主从复制是 MySQL 高可用架构的基础,用于实现数据备份、读写分离、故障恢复等功能。
主从复制作用
| 作用 | 说明 | 典型场景 |
|---|---|---|
| 数据备份 | 从库作为热备 | 灾难恢复 |
| 读写分离 | 主库写,从库读 | 高并发读 |
| 数据分析 | 从库执行分析查询 | BI 报表 |
| 故障恢复 | 主库故障切换到从库 | 高可用 |
复制架构
典型架构:
主库(Master)
↓
从库 1(Slave)
从库 2(Slave)
从库 3(Slave)
级联复制:
主库 → 从库 1 → 从库 2 → 从库 3
双主复制:
主库 1 ↔ 主库 2(互为主从)
主从复制底层原理
复制三线程模型
主从复制涉及 3 个线程:
1. 主库:Binlog Dump Thread
- 每个从库对应一个
- 读取 binlog 发送给从库
2. 从库:I/O Thread
- 连接主库,请求 binlog
- 接收 binlog 写入 relay log
3. 从库:SQL Thread
- 读取 relay log
- 重放 SQL 语句
sequenceDiagram
participant Master as 主库
participant Dump as Binlog Dump Thread
participant IO as 从库 I/O Thread
participant SQL as 从库 SQL Thread
participant Relay as Relay Log
Master->>Dump: 事务提交,写 binlog
IO->>Master: 请求 binlog
Dump->>IO: 发送 binlog 事件
IO->>Relay: 写入 relay log
SQL->>Relay: 读取 relay log
SQL->>Master: 重放 SQL
binlog 详解
binlog(Binary Log) 是 MySQL 的二进制日志,记录所有数据变更操作。
-- 查看 binlog 配置
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
-- 查看 binlog 文件
SHOW BINARY LOGS;
-- 查看当前 binlog 文件
SHOW MASTER STATUS;
binlog 格式:
| 格式 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| STATEMENT | 记录 SQL 语句 | 日志量小 | 可能不一致 |
| ROW | 记录行变更 | 数据一致 | 日志量大 |
| MIXED | 混合模式(默认) | 兼顾两者 | 复杂 |
-- 推荐配置
SET GLOBAL binlog_format = 'ROW';
-- 或混合模式
SET GLOBAL binlog_format = 'MIXED';
binlog 结构:
# at 4
#240101 10:00:00 server id 1 end_log_pos 123 CRC32 0x12345678
# Start: binlog v 4, server v 8.0.32 created 240101 10:00:00
# at 123
#240101 10:00:01 server id 1 end_log_pos 234 CRC32 0x23456789
# Query thread_id=1 exec_time=0 error_code=0
use `test`;
SET TIMESTAMP=1704067201;
INSERT INTO users (id, name) VALUES (1, 'Alice');
relay log 详解
relay log 是从库的中继日志,存储从主库接收的 binlog。
-- 查看 relay log 配置
SHOW VARIABLES LIKE 'relay_log';
SHOW VARIABLES LIKE 'relay_log_purge';
-- 查看 relay log 状态
SHOW SLAVE STATUS\G
-- 查看当前 relay log 文件
SHOW RELAYLOG EVENTS;
relay log 管理:
-- 自动清理(默认开启)
SET GLOBAL relay_log_purge = 1;
-- 手动清理
PURGE RELAY LOGS TO 'relay-bin.000100';
-- 重置从库
RESET SLAVE ALL;
复制配置与搭建
基础复制配置
主库配置(my.cnf):
[mysqld]
# 开启 binlog
log_bin = mysql-bin
# binlog 格式
binlog_format = ROW
# server id(必须唯一)
server_id = 1
# binlog 过期时间(秒)
binlog_expire_logs_seconds = 604800
# 同步 binlog 到磁盘
sync_binlog = 1
从库配置(my.cnf):
[mysqld]
# server id(必须唯一)
server_id = 2
# relay log
relay_log = mysql-relay-bin
# 只读(防止误写)
read_only = 1
# 超级用户可写
super_read_only = 1
搭建主从复制
-- 1. 主库创建复制用户
CREATE USER 'repl'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
-- 2. 主库查看 binlog 位置
SHOW MASTER STATUS;
-- File: mysql-bin.000001
-- Position: 154
-- 3. 从库配置主库信息
CHANGE MASTER TO
MASTER_HOST='192.168.1.100',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;
-- 4. 启动复制
START SLAVE;
-- 5. 查看复制状态
SHOW SLAVE STATUS\G
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- Seconds_Behind_Master: 0
使用 GTID 复制
GTID(Global Transaction Identifier) 是全局事务 ID,简化复制管理。
-- 开启 GTID(MySQL 5.6+)
# my.cnf
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
-- 从库配置(使用 GTID)
CHANGE MASTER TO
MASTER_HOST='192.168.1.100',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_AUTO_POSITION = 1; -- 自动定位 GTID
START SLAVE;
GTID 优势:
- 无需指定 binlog 文件名和位置
- 主从切换更简单
- 避免复制错误
并行复制
MySQL 5.7+ 支持并行复制,提升从库回放速度。
-- 配置并行复制
# my.cnf
[mysqld]
# 基于组的提交(推荐)
slave_parallel_type = LOGICAL_CLOCK
# 并行 worker 数量
slave_parallel_workers = 4
# 基于数据库并行
# slave_parallel_type = DATABASE
并行复制原理:
主库提交事务时,同一组提交的事务可以并行回放。
组提交:
事务 1 ─┐
事务 2 ─┼─ 同一组,可并行回放
事务 3 ─┘
事务 4 ─ 下一组
复制模式详解
异步复制(默认)
主库 从库
│ │
├─ 写 binlog │
├─ 提交事务 │
├─ 返回客户端 │
│ │
│─────── binlog ─────────>│
│ ├─ 写入 relay log
│ ├─ SQL 线程回放
│ └─ 完成
特点:
- ✅ 主库不等待从库,性能最好
- ❌ 主库故障可能丢失数据
半同步复制
主库 从库
│ │
├─ 写 binlog │
├─ 等待 ACK │
│ │
│─────── binlog ─────────>│
│ ├─ 写入 relay log
│ ├─ 返回 ACK
│<──────── ACK ────────────│
├─ 提交事务 │
├─ 返回客户端 │
配置:
-- 主库
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = ON;
SET GLOBAL rpl_semi_sync_master_timeout = 10000; -- 10 秒超时
-- 从库
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = ON;
START SLAVE;
特点:
- ✅ 保证至少一个从库收到 binlog
- ⚠️ 性能略有下降
全同步复制(MySQL 8.0.17+)
-- 使用 Group Replication 实现
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
-- 配置组复制
SET GLOBAL group_replication_bootstrap_group = ON;
START GROUP_REPLICATION;
特点:
- ✅ 所有从库确认才提交
- ❌ 性能最差
增强半同步(MySQL 5.7+)
AFTER_COMMIT 模式(默认):
主库写 binlog → 从库收到 → 主库提交 → 返回
AFTER_SYNC 模式(更强):
主库写 binlog → 从库收到 → 主库提交 → 从库回放 → 返回
配置:
SET GLOBAL rpl_semi_sync_master_wait_point = 'AFTER_SYNC';
复制状态监控
关键指标
-- 查看复制状态
SHOW SLAVE STATUS\G
-- 关键字段:
Slave_IO_Running: Yes # I/O 线程状态
Slave_SQL_Running: Yes # SQL 线程状态
Seconds_Behind_Master: 0 # 复制延迟
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 1234 # 已读取的 binlog 位置
Relay_Log_File: relay-bin.000001
Relay_Log_Pos: 456 # relay log 位置
Exec_Master_Log_Pos: 456 # 已执行的 binlog 位置
Last_Error: # 错误信息
复制延迟监控
-- 方法 1:Seconds_Behind_Master
SHOW SLAVE STATUS;
-- Seconds_Behind_Master: 10 # 延迟 10 秒
-- 方法 2:时间戳对比
-- 主库
SELECT NOW();
-- 从库
SELECT NOW();
SELECT TIMESTAMPDIFF(SECOND, NOW(), @master_time) AS delay;
-- 方法 3:pt-heartbeat(推荐)
# 主库
pt-heartbeat --create-slave-heartbeat --update h=master
# 从库
pt-heartbeat --check h=slave
复制错误处理
-- 查看错误
SHOW SLAVE STATUS\G
-- Last_Error: Duplicate entry '1' for key 'PRIMARY'
-- 跳过错误(不推荐)
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;
-- 跳过指定 GTID(MySQL 5.7+)
STOP SLAVE;
SET GLOBAL gtid_next = 'xxxxx:123';
BEGIN; COMMIT;
SET GLOBAL gtid_next = 'AUTOMATIC';
START SLAVE;
-- 重置从库
STOP SLAVE;
RESET SLAVE ALL;
CHANGE MASTER TO ...;
START SLAVE;
最佳实践
配置建议
[mysqld]
# 主库
log_bin = mysql-bin
binlog_format = ROW
server_id = 1
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
# 从库
server_id = 2
read_only = 1
super_read_only = 1
relay_log_purge = 1
slave_parallel_workers = 4
slave_parallel_type = LOGICAL_CLOCK
# 半同步复制
rpl_semi_sync_master_enabled = ON
rpl_semi_sync_slave_enabled = ON
监控告警
# Prometheus 监控
groups:
- name: mysql_replication
rules:
- alert: ReplicationLag
expr: mysql_slave_status_seconds_behind_master > 60
for: 5m
labels:
severity: warning
- alert: ReplicationStopped
expr: mysql_slave_status_slave_io_running == 0
labels:
severity: critical
参考资料
- MySQL 官方文档 - 复制
- 《高性能 MySQL》第 10 章:复制
- 《MySQL 技术内幕:InnoDB 存储引擎》第 10 章