强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

MySQL 完全指南 / 第 12 章:主从复制

第 12 章:主从复制

主从复制是 MySQL 高可用、读写分离的基础。本章详解复制原理与配置。


12.1 复制原理

12.1.1 复制流程

主库 (Master)                     从库 (Slave)
┌─────────────┐                  ┌─────────────┐
│ 执行写操作   │                  │              │
│ ↓           │                  │              │
│ 写入 Binlog  │───Binlog Dump──→│ I/O Thread   │
│             │                  │ ↓            │
│             │                  │ 写入 Relay Log│
│             │                  │ ↓            │
│             │                  │ SQL Thread   │
│             │                  │ ↓            │
│             │                  │ 重放 SQL     │
└─────────────┘                  └─────────────┘

三个关键线程:

  1. Binlog Dump Thread(主库):读取 Binlog 发送给从库
  2. I/O Thread(从库):接收 Binlog 并写入 Relay Log
  3. SQL Thread(从库):读取 Relay Log 并重放

12.1.2 复制格式

格式说明优点缺点
STATEMENT记录 SQL 语句日志量小非确定性函数可能不一致
ROW记录行变更数据一致性好日志量大
MIXED自动选择兼顾两者不是所有场景都切换
-- 查看复制格式
SHOW VARIABLES LIKE 'binlog_format';

-- 推荐使用 ROW 格式
SET GLOBAL binlog_format = 'ROW';

12.2 异步复制配置

12.2.1 主库配置

# my.cnf - 主库
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog-format = ROW
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
-- 创建复制用户
CREATE USER 'repl'@'%' IDENTIFIED BY 'Repl!Str0ngPass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

-- 查看主库状态
SHOW MASTER STATUS;
-- +------------------+----------+--------------+
-- | File             | Position | Binlog_Do_DB |
-- +------------------+----------+--------------+
-- | mysql-bin.000003 | 785      |              |
-- +------------------+----------+--------------+

12.2.2 从库配置

# my.cnf - 从库
[mysqld]
server-id = 2
relay-log = relay-bin
read-only = ON
super-read-only = ON
-- 配置主库连接信息(MySQL 8.0.23+)
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST = '192.168.1.100',
    SOURCE_PORT = 3306,
    SOURCE_USER = 'repl',
    SOURCE_PASSWORD = 'Repl!Str0ngPass',
    SOURCE_LOG_FILE = 'mysql-bin.000003',
    SOURCE_LOG_POS = 785;

-- 启动复制
START REPLICA;

-- 查看复制状态
SHOW REPLICA STATUS\G

12.2.3 关键状态指标

SHOW REPLICA STATUS\G

-- 重点关注:
-- Replica_IO_Running: Yes     ← I/O 线程是否运行
-- Replica_SQL_Running: Yes    ← SQL 线程是否运行
-- Seconds_Behind_Source: 0    ← 复制延迟(秒)
-- Last_Error:                 ← 最后错误信息
-- Retrieved_Source_Log_File   ← 已获取的主库 Binlog 文件
-- Executed_Source_Log_File    ← 已执行的主库 Binlog 文件

12.3 半同步复制(Semi-Synchronous Replication)

12.3.1 原理

异步复制:主库提交后不等从库确认,可能丢失数据。 半同步复制:主库至少等一个从库确认收到 Binlog 后才返回成功。

异步复制:主库 → 写 Binlog → 返回客户端
半同步复制:主库 → 写 Binlog → 等待从库确认 → 返回客户端
                              ↘ 从库收到并写入 Relay Log → 确认

12.3.2 配置

-- 主库安装插件
INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';
SET GLOBAL rpl_semi_sync_source_enabled = ON;
SET GLOBAL rpl_semi_sync_source_timeout = 5000;  -- 超时5秒降级为异步

-- 从库安装插件
INSTALL PLUGIN rpl_semi_sync_replica SONAME 'semisync_replica.so';
SET GLOBAL rpl_semi_sync_replica_enabled = ON;

-- 重启复制
STOP REPLICA;
START REPLICA;

12.4 GTID 复制

12.4.1 概述

GTID(Global Transaction Identifier)为每个事务分配全局唯一标识,简化复制管理。

格式:source_uuid:transaction_id 示例:3e11fa47-71ca-11e1-9e33-c80aa9429562:23

12.4.2 配置

# my.cnf - 主库和从库都需要
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
log-bin = mysql-bin
server-id = 1  # 每个实例不同
-- 从库配置 GTID 复制
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST = '192.168.1.100',
    SOURCE_USER = 'repl',
    SOURCE_PASSWORD = 'Repl!Str0ngPass',
    SOURCE_AUTO_POSITION = 1;  -- 使用 GTID 自动定位

START REPLICA;

12.4.3 GTID 优势

维度传统复制GTID 复制
故障切换需要手动指定 Binlog 文件和位置自动定位
主从切换复杂简单
数据一致性需要额外检查内置保障
跳过事务复杂简单

12.5 复制延迟处理

12.5.1 延迟监控

-- 查看延迟
SHOW REPLICA STATUS\G
-- Seconds_Behind_Source

-- 更精确的延迟监控(基于心跳)
-- 主库设置
SET GLOBAL rpl_semi_sync_source_timeout = 5000;

-- 查看延迟
SELECT * FROM performance_schema.replication_connection_status;
SELECT * FROM performance_schema.replication_applier_status_by_worker;

12.5.2 延迟优化

-- 1. 使用多线程复制(MySQL 5.7+)
SET GLOBAL slave_parallel_workers = 4;
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';  -- 5.7+
SET GLOBAL replica_parallel_workers = 4;  -- 8.0+
SET GLOBAL replica_parallel_type = 'LOGICAL_CLOCK';

-- 2. 从库配置
[mysqld]
replica_parallel_workers = 8
replica_parallel_type = LOGICAL_CLOCK
replica_preserve_commit_order = ON

12.6 延迟从库(Delayed Replica)

-- 设置从库延迟 1 小时执行(用于数据误操作恢复)
CHANGE REPLICATION SOURCE TO SOURCE_DELAY = 3600;

-- 如果主库误删数据,可以在延迟从库上找到数据
STOP REPLICA;
START REPLICA UNTIL SQL_BEFORE_GTIDS = 'gtid_to_stop_before';

12.7 主从切换

-- 1. 确认从库已追上主库
SHOW REPLICA STATUS\G  -- Seconds_Behind_Source = 0

-- 2. 主库设为只读
SET GLOBAL read_only = ON;
SET GLOBAL super_read_only = ON;

-- 3. 从库停止复制,设为可写
STOP REPLICA;
SET GLOBAL read_only = OFF;
SET GLOBAL super_read_only = OFF;

-- 4. 其他从库指向新主库
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST = 'new_master_ip',
    SOURCE_AUTO_POSITION = 1;
START REPLICA;

业务场景

场景 1:读写分离架构

应用层
├── 写操作 → 主库
└── 读操作 → 从库 1 / 从库 2 / 从库 3

使用 ProxySQL 实现自动读写分离:

-- ProxySQL 配置(简化示例)
-- 定义后端 MySQL 实例
INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES
(10, '192.168.1.100', 3306),  -- 写组
(20, '192.168.1.101', 3306),  -- 读组
(20, '192.168.1.102', 3306);  -- 读组

-- 读写分离规则
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup) VALUES
(1, 1, '^SELECT.*FOR UPDATE', 10),  -- SELECT FOR UPDATE 走主库
(2, 1, '^SELECT', 20);              -- 普通 SELECT 走从库

扩展阅读