Skip to content
清晨的一缕阳光
返回

MySQL 主从复制原理

核心概念

主从复制是 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 优势:

并行复制

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;

特点:

全同步复制(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

参考资料


分享这篇文章到:

上一篇文章
Spring Boot RBAC 权限控制
下一篇文章
Spring Boot 4 快速入门