全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-15 10 分钟 ✍️ juanwangdev

MySQL 主从复制与读写分离

主从复制是 MySQL 高可用架构的基础,读写分离提升系统吞吐量。

主从复制原理

复制流程

SQL
┌──────────────┐                    ┌──────────────┐
│    Master    │                    │    Slave     │
├──────────────┤                    ├──────────────┤
│              │  Binlog Dump     ─▶│  I/O Thread  │
│  Binlog      │◀─────────────────  │              │
│              │                    │  Relay Log   │
│              │                    │              │
│              │                    │  SQL Thread  │
│              │                    │      ↓       │
│  Data        │                    │  Data        │
└──────────────┘                    └──────────────┘

复制线程:

  • Binlog Dump Thread:主库线程,发送 binlog 到从库
  • I/O Thread:从库线程,接收 binlog 写入 relay log
  • SQL Thread:从库线程,执行 relay log 中的事件

复制位置记录

SQL
-- 主库记录
Master_Log_File: 当前 binlog 文件
Read_Master_Log_Pos: 已读取的位置

-- 从库记录
Relay_Log_File: relay log 文件
Relay_Log_Pos: relay log 执行位置
Exec_Master_Log_Pos: 已执行的主库位置

复制模式对比

三种复制模式

模式说明数据安全性能
异步复制主库提交后即返回,不等待从库
半同步复制主库等待至少一个从库确认
组复制 (MGR)多主/单主集群,Paxos 协议

1. 异步复制(默认)

SQL
Master 提交事务 ─▶ 返回成功 ─▶ Binlog 发送到 Slave

数据丢失风险:主库宕机时,未同步的 binlog 丢失

2. 半同步复制

ini
Master 提交事务 ─▶ 等待 Slave ACK ─▶ 返回成功
                    │
                    ├─ 超时(rpl_semi_sync_master_timeout)
                    │   则降级为异步
                    │
                    └─ 收到 ACK,确认复制完成

配置半同步复制:

SQL
-- 主库安装插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

-- 从库安装插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

-- 主库配置
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 1000;  -- 1秒超时
SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 1;  -- 等待1个从库

-- 从库配置
SET GLOBAL rpl_semi_sync_slave_enabled = 1;

-- 重启从库复制
STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

3. MySQL Group Replication (MGR)

ini
-- 安装插件
INSTALL PLUGIN group_replication SONAME 'group_replication.so';

-- 配置参数
SET GLOBAL group_replication_group_name = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee';
SET GLOBAL group_replication_start_on_boot = ON;
SET GLOBAL group_replication_local_address = '192.168.1.101:33061';
SET GLOBAL group_replication_group_seeds = '192.168.1.101:33061,192.168.1.102:33061';

-- 启动组复制
START GROUP_REPLICATION;

主从复制配置

主库配置

SQL
[mysqld]
# 服务器唯一ID
server-id = 1

# 开启 binlog
log-bin = mysql-bin
binlog_format = ROW
binlog_row_image = FULL

# 必要参数
gtid_mode = ON
enforce_gtid_consistency = ON

# 复制用户
# CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_password';
# GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
SQL
-- 创建复制用户
CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'repl_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%';
FLUSH PRIVILEGES;

-- 查看主库状态
SHOW MASTER STATUS;

从库配置

Java
[mysqld]
# 服务器唯一ID
server-id = 2

# 开启 relay log
relay-log = relay-bin
relay-log-index = relay-bin.index

# GTID 配置
gtid_mode = ON
enforce_gtid_consistency = ON

# 只读模式
read_only = ON
super_read_only = ON

# 并行复制
slave_parallel_workers = 4
slave_parallel_type = LOGICAL_CLOCK
SQL
-- 配置复制(GTID 模式)
CHANGE MASTER TO
    MASTER_HOST = '192.168.1.101',
    MASTER_PORT = 3306,
    MASTER_USER = 'repl',
    MASTER_PASSWORD = 'repl_password',
    MASTER_AUTO_POSITION = 1;

-- 启动复制
START SLAVE;

-- 查看状态
SHOW SLAVE STATUS\G

关键状态指标

SQL
SHOW SLAVE STATUS\G

-- 关键字段
Slave_IO_Running: Yes          -- I/O 线程运行状态
Slave_SQL_Running: Yes         -- SQL 线程运行状态
Seconds_Behind_Master: 0       -- 复制延迟秒数
Retrieved_Gtid_Set: ...        -- 已接收的 GTID
Executed_Gtid_Set: ...         -- 已执行的 GTID
Last_IO_Error: ...             -- I/O 错误信息
Last_SQL_Error: ...            -- SQL 错误信息

读写分离实现

应用层实现

Java
// Java 示例:根据操作类型选择数据源
public Connection getConnection(String operationType) {
    if (operationType.equals("write")) {
        return masterDataSource.getConnection();
    } else {
        return slaveDataSource.getConnection();
    }
}

// Spring 事务注解
@Transactional(readOnly = true)  // 自动路由到从库
public User getUser(Long id) {
    return userDao.selectById(id);
}

@Transactional  // 默认路由到主库
public void updateUser(User user) {
    userDao.update(user);
}

中间件实现

中间件说明
ProxySQL自动解析 SQL,路由到对应主机组
MySQL RouterMySQL 官方路由组件
MaxScaleMariaDB 出品,功能强大
ShardingSphere客户端侧读写分离

ProxySQL 读写分离配置

SQL
-- 写操作路由主库(hostgroup 10)
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (1, 1, '^INSERT|^UPDATE|^DELETE|^REPLACE', 10, 1);

-- 读操作路由从库(hostgroup 20)
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (2, 1, '^SELECT', 20, 1);

复制延迟处理

延迟原因

原因说明
大事务单事务执行时间过长
从库负载高从库查询压力大
网络延迟主从之间网络慢
单线程复制SQL Thread 单线程执行

优化方案

1. 并行复制

SQL
-- MySQL 5.7+ 并行复制
SET GLOBAL slave_parallel_workers = 8;
SET GLOBAL slave_parallel_type = LOGICAL_CLOCK;
SET GLOBAL slave_preserve_commit_order = ON;

2. 分库分表减少单库压力

SQL
大事务拆分:
┌──────────────┐          ┌──────────────┐
│  大事务      │   拆分   │  小事务1     │
│  100万行     │  ────▶  │  1万行       │
│              │          │  小事务2     │
│              │          │  ...         │
└──────────────┘          └──────────────┘

3. 从库延迟强制路由主库

SQL
// 关键业务强制读主库
public Order getOrder(Long orderId) {
    // 订单状态等关键数据必须读主库
    return masterDataSource.query(orderId);
}

// 非关键业务可读从库
public Order getOrderSnapshot(Long orderId) {
    return slaveDataSource.query(orderId);
}

4. 多级复制

SQL
Master ─▶ Slave1(实时复制)
           │
           └─▶ Slave2(延迟复制,分担读取压力)
           │
           └─▶ Slave3(延迟复制,分担读取压力)
text
-- 延迟复制配置(延迟 1 小时)
CHANGE MASTER TO
    MASTER_HOST = '192.168.1.101',
    MASTER_DELAY = 3600;  -- 延迟秒数

START SLAVE;

复制故障处理

IO 线程故障

text
-- 常见错误:连接失败、认证失败
-- 处理步骤
STOP SLAVE;
-- 检查复制用户权限、网络连通性
-- 重新配置
CHANGE MASTER TO MASTER_PASSWORD = 'new_password';
START SLAVE;

SQL 線程故障

text
-- 常见错误:主键冲突、数据不一致
-- 处理步骤
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;  -- 跳过 1 个事件
START SLAVE;

-- 或使用 GTID 跳过
SET GTID_NEXT = 'aaaa-bbbb-cccc-dddd-eeee:123';
BEGIN;
COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START SLAVE;

主从切换

text
-- 1. 停止原主库写入
FLUSH TABLES WITH READ LOCK;

-- 2. 确认从库同步完成
SHOW SLAVE STATUS;
-- Seconds_Behind_Master = 0

-- 3. 从库提升为主库
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only = OFF;
SET GLOBAL super_read_only = OFF;

-- 4. 其他从库指向新主库
CHANGE MASTER TO MASTER_HOST = '192.168.1.102';
START SLAVE;

监控指标

text
-- 复制状态监控
SELECT
    variable_name,
    variable_value
FROM performance_schema.replication_connection_status
WHERE channel_name = '';

-- 复制延迟监控
SELECT
    variable_value AS seconds_behind_master
FROM performance_schema.replication_applier_status_by_coordinator
WHERE channel_name = '';

-- 复制线程状态
SHOW PROCESSLIST;
-- Id: xxx, User: system user, Command: Connect

要点总结

  1. 复制原理:Binlog Dump → I/O Thread → Relay Log → SQL Thread
  2. 三种模式:异步(默认)、半同步(推荐)、组复制(高可用)
  3. GTID 复制:推荐使用,简化配置和故障恢复
  4. 读写分离:应用层或中间件实现,写主读从
  5. 复制延迟:并行复制、大事务拆分、关键业务读主库
  6. 故障处理:跳过错误事件、主从切换流程

📝 发现内容有误?点击此处直接编辑

← 上一篇 MySQL ProxySQL与负载均衡
下一篇 → MySQL 分布式事务与XA协议
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库