数据库2024-06-0425 分钟阅读

MySQL 主从复制完全指南:从原理到实战配置

深入讲解 MySQL 主从复制的工作原理、应用场景、配置步骤和常见问题,帮助你快速搭建高可用的 MySQL 数据库架构

MySQL主从复制数据库高可用运维

什么是 MySQL 主从复制

MySQL 主从复制(Master-Slave Replication)是指将主数据库(Master)的数据自动复制到一个或多个从数据库(Slave)的过程。这是一种异步复制机制,主库执行的所有写操作都会被记录并传输到从库执行。

核心概念

  • 主库(Master):接收写操作的数据库服务器
  • 从库(Slave):接收主库数据并保持同步的数据库服务器
  • Binary Log(binlog):主库记录所有数据变更的二进制日志
  • Relay Log:从库接收并存储主库 binlog 的中继日志
  • 复制线程:负责数据复制的 IO 线程和 SQL 线程

主从复制的工作原理

MySQL 主从复制的核心流程分为三个步骤:

1. 主库记录变更

主库将所有数据变更操作(INSERT、UPDATE、DELETE)记录到 Binary Log(binlog)中。

-- 主库执行写操作
INSERT INTO users (name, email) VALUES ('张三', 'zhangsan@example.com');
-- 这条操作会被记录到 binlog

重点理解

  • binlog 是 MySQL 的二进制日志,记录了所有对数据库的修改操作
  • binlog 有三种格式:STATEMENT(语句级)、ROW(行级)、MIXED(混合)
  • 推荐使用 ROW 格式,因为它最安全,能准确记录每一行的变化

2. 从库读取日志

从库的 IO 线程 连接到主库,读取主库的 binlog,并将其写入到从库本地的 Relay Log(中继日志)中。

IO 线程的工作流程

  1. 从库 IO 线程连接到主库
  2. 主库创建一个 binlog dump 线程
  3. dump 线程读取 binlog 并发送给从库
  4. 从库 IO 线程接收数据并写入 Relay Log

3. 从库重放日志

从库的 SQL 线程 读取 Relay Log,并在从库上重新执行这些 SQL 语句,从而实现数据同步。

SQL 线程的工作流程

  1. SQL 线程读取 Relay Log 中的事件
  2. 解析事件并转换为 SQL 语句
  3. 在从库上执行这些 SQL 语句
  4. 更新复制位置信息

MySQL 主从复制架构图

复制的关键概念

1. 复制位置(Position)

  • 主库的 binlog 文件名和位置
  • 从库记录已经复制到的位置
  • 用于断点续传,从库重启后从上次位置继续

2. 复制延迟

  • 主库执行完成到从库执行完成的时间差
  • 通过 Seconds_Behind_Master 查看
  • 延迟过大会影响读写分离的数据一致性

3. 复制过滤

  • 可以指定只复制某些数据库或表
  • 使用 binlog-do-dbreplicate-do-db 配置
  • 减少不必要的数据传输

主从复制的应用场景

1. 读写分离

将写操作发送到主库,读操作分发到多个从库,提升系统整体性能。

应用层
  ↓
写操作 → 主库(Master)
读操作 → 从库1、从库2、从库3(负载均衡)

实现方式

  • 应用层实现:代码中判断读写操作,分别连接不同数据库
  • 中间件实现:使用 MySQL Proxy、ProxySQL、MaxScale 等
  • ORM 框架:如 Django、MyBatis 支持主从配置

注意事项

  • 主从延迟可能导致读到旧数据
  • 对实时性要求高的查询应该读主库
  • 可以使用强制主库读取标记

2. 数据备份

从库可以作为实时备份,主库故障时可以快速切换。

优势

  • 实时备份,数据丢失风险小
  • 不影响主库性能
  • 可以在从库上执行备份操作

备份策略

# 在从库上执行全量备份
mysqldump -u root -p \
  --single-transaction \
  --master-data=2 \
  --all-databases > backup.sql

3. 数据分析

在从库上执行复杂的统计查询,避免影响主库的业务性能。

适用场景

  • 大数据量的报表查询
  • 数据挖掘和分析
  • 慢查询测试

4. 跨地域部署

在不同地域部署从库,提供就近访问,降低延迟。

北京机房(主库)
    ↓
    ├─→ 上海机房(从库1)→ 服务华东用户
    ├─→ 广州机房(从库2)→ 服务华南用户
    └─→ 成都机房(从库3)→ 服务西南用户

5. 灰度发布和升级

在从库上测试新版本 MySQL,验证兼容性后再升级主库。

实战:配置 MySQL 主从复制

环境准备

  • 主库服务器:192.168.1.100(CentOS 7 + MySQL 8.0)
  • 从库服务器:192.168.1.101(CentOS 7 + MySQL 8.0)
  • 前提条件:两台服务器都已安装 MySQL 8.0

步骤 1:配置主库

1.1 修改主库配置文件

编辑 /etc/my.cnf,添加以下配置:

[mysqld]
# 服务器唯一ID,主库和从库必须不同
server-id = 1

# 启用二进制日志
log-bin = mysql-bin

# 二进制日志格式(推荐使用 ROW)
binlog_format = ROW

# 需要复制的数据库(可选,不指定则复制所有数据库)
# binlog-do-db = mydb

# 不需要复制的数据库(可选)
binlog-ignore-db = mysql
binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema
binlog-ignore-db = sys

# binlog 过期时间(天)
expire_logs_days = 7

# 每次事务提交后立即刷新 binlog 到磁盘(保证数据安全)
sync_binlog = 1

1.2 重启主库

sudo systemctl restart mysqld

1.3 创建复制用户

登录主库 MySQL,创建专门用于复制的用户:

-- 登录 MySQL
mysql -u root -p

-- 创建复制用户
CREATE USER 'repl_user'@'192.168.1.101' IDENTIFIED BY 'StrongPassword123!';

-- 授予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'192.168.1.101';

-- 刷新权限
FLUSH PRIVILEGES;

1.4 查看主库状态

记录主库的 binlog 文件名和位置,后续配置从库时需要用到:

SHOW MASTER STATUS;

输出示例:

+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      156 |              | mysql,...        |                   |
+------------------+----------+--------------+------------------+-------------------+

重要:记住 FilePosition 的值!

步骤 2:配置从库

2.1 修改从库配置文件

编辑 /etc/my.cnf,添加以下配置:

[mysqld]
# 服务器唯一ID(必须与主库不同)
server-id = 2

# 启用中继日志
relay-log = mysql-relay-bin

# 从库只读(可选,防止从库被误写入)
read_only = 1

# 需要复制的数据库(可选)
# replicate-do-db = mydb

# 不需要复制的数据库(可选)
replicate-ignore-db = mysql
replicate-ignore-db = information_schema
replicate-ignore-db = performance_schema
replicate-ignore-db = sys

2.2 重启从库

sudo systemctl restart mysqld

2.3 配置主从关系

登录从库 MySQL,配置主库信息:

-- 登录 MySQL
mysql -u root -p

-- 停止从库复制(如果之前配置过)
STOP SLAVE;

-- 配置主库信息
CHANGE MASTER TO
  MASTER_HOST='192.168.1.100',           -- 主库IP
  MASTER_USER='repl_user',                -- 复制用户
  MASTER_PASSWORD='StrongPassword123!',   -- 复制用户密码
  MASTER_LOG_FILE='mysql-bin.000001',     -- 主库binlog文件名
  MASTER_LOG_POS=156;                     -- 主库binlog位置

-- 启动从库复制
START SLAVE;

2.4 查看从库状态

SHOW SLAVE STATUS\G

重点关注以下字段:

Slave_IO_Running: Yes      -- IO线程运行状态
Slave_SQL_Running: Yes     -- SQL线程运行状态
Seconds_Behind_Master: 0   -- 从库延迟秒数
Last_IO_Error:             -- IO错误信息(应为空)
Last_SQL_Error:            -- SQL错误信息(应为空)

如果两个线程都是 Yes,且没有错误信息,说明主从复制配置成功!

步骤 3:测试主从复制

3.1 在主库创建测试数据

-- 在主库执行
CREATE DATABASE test_replication;
USE test_replication;

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50),
  email VARCHAR(100),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO users (name, email) VALUES 
  ('张三', 'zhangsan@example.com'),
  ('李四', 'lisi@example.com'),
  ('王五', 'wangwu@example.com');

3.2 在从库验证数据

-- 在从库执行
USE test_replication;
SELECT * FROM users;

如果能看到相同的数据,说明主从复制工作正常!

常见问题与解决方案

问题 1:从库复制延迟

现象Seconds_Behind_Master 值很大

原因分析

  • 主库写入压力过大,从库处理速度跟不上
  • 从库硬件性能不足(CPU、内存、磁盘 IO)
  • 网络带宽限制或网络延迟高
  • 从库上有其他查询占用资源
  • 大事务导致的延迟(如一次性插入大量数据)

解决方案

  1. 使用并行复制(MySQL 5.7+)
-- 启用并行复制
STOP SLAVE SQL_THREAD;
SET GLOBAL slave_parallel_workers = 4;
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
START SLAVE SQL_THREAD;

-- 查看并行复制状态
SHOW PROCESSLIST;
  1. 优化从库硬件
  • 使用 SSD 硬盘提升 IO 性能
  • 增加内存,提高缓存命中率
  • 升级 CPU,提升处理能力
  1. 优化主库写入
  • 批量操作改为小批量多次
  • 避免大事务,拆分为小事务
  • 优化索引,减少写入时间
  1. 使用半同步复制
-- 主库启用半同步
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 1000;

问题 2:复制线程停止

现象Slave_IO_RunningSlave_SQL_RunningNo

排查步骤

-- 查看详细错误信息
SHOW SLAVE STATUS\G

-- 重点关注这些字段
-- Last_IO_Error: IO 线程错误信息
-- Last_SQL_Error: SQL 线程错误信息
-- Last_SQL_Errno: 错误代码

常见错误及解决

错误 1062:主键冲突

原因:从库已存在相同主键的记录

解决方案

-- 方法 1:跳过一个错误(谨慎使用)
STOP SLAVE;
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;

-- 方法 2:删除冲突记录后重新同步
-- 先在从库上删除冲突记录
DELETE FROM table_name WHERE id = xxx;
START SLAVE;

-- 方法 3:使用 slave_skip_errors(不推荐生产环境)
-- 在 my.cnf 中配置
slave-skip-errors = 1062

错误 1032:记录不存在

原因:从库缺少主库要更新或删除的记录

解决方案

-- 跳过该错误
STOP SLAVE;
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;

-- 或者从主库重新导入数据

错误 2013:连接丢失

原因:网络不稳定或主库重启

解决方案

-- 重新启动复制
STOP SLAVE;
START SLAVE;

-- 如果持续出现,检查网络和主库状态

问题 3:主库 binlog 被清理

现象:从库找不到主库的 binlog 文件

错误信息

Got fatal error 1236 from master when reading data from binary log: 
'Could not find first log file name in binary log index file'

解决方案:重新初始化从库

# 1. 在主库备份数据
mysqldump -u root -p \
  --all-databases \
  --master-data=2 \
  --single-transaction \
  --quick \
  --lock-tables=false > master_backup.sql

# 2. 查看备份文件中的 binlog 位置
head -50 master_backup.sql | grep "CHANGE MASTER"
# 输出类似:-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000010', MASTER_LOG_POS=154;

# 3. 将备份文件传输到从库
scp master_backup.sql root@slave-server:/tmp/

# 4. 在从库导入数据
mysql -u root -p < /tmp/master_backup.sql

# 5. 重新配置主从关系
mysql -u root -p
STOP SLAVE;
CHANGE MASTER TO
  MASTER_HOST='192.168.1.100',
  MASTER_USER='repl_user',
  MASTER_PASSWORD='password',
  MASTER_LOG_FILE='mysql-bin.000010',
  MASTER_LOG_POS=154;
START SLAVE;

问题 4:主从数据不一致

检查方法

# 使用 pt-table-checksum 工具检查
pt-table-checksum \
  --host=master-host \
  --user=root \
  --password=password \
  --databases=mydb

# 使用 pt-table-sync 修复不一致
pt-table-sync \
  --execute \
  --sync-to-master \
  h=slave-host,u=root,p=password

预防措施

  • 使用 ROW 格式的 binlog
  • 启用 GTID 模式
  • 定期检查主从一致性
  • 避免在从库上进行写操作

高级配置:半同步复制

半同步复制(Semi-Synchronous Replication)是介于异步复制和同步复制之间的一种方案,可以减少数据丢失的风险。

工作原理

异步复制(默认)

  • 主库执行完事务后立即返回给客户端
  • 不等待从库确认
  • 性能最好,但主库宕机可能丢失数据

半同步复制

  • 主库执行完事务后,等待至少一个从库确认接收到 binlog
  • 从库写入 Relay Log 后发送确认
  • 主库收到确认后才返回给客户端
  • 性能略有下降,但数据更安全

同步复制

  • 主库等待所有从库执行完事务
  • 性能最差,但数据最安全
  • MySQL 原生不支持,需要使用 MySQL Cluster

配置半同步复制

主库配置

-- 1. 安装半同步插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

-- 2. 启用半同步
SET GLOBAL rpl_semi_sync_master_enabled = 1;

-- 3. 设置超时时间(毫秒)
-- 如果超时,自动降级为异步复制
SET GLOBAL rpl_semi_sync_master_timeout = 1000;

-- 4. 设置等待从库数量(MySQL 5.7+)
SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 1;

-- 5. 持久化配置(写入 my.cnf)
-- [mysqld]
-- rpl_semi_sync_master_enabled = 1
-- rpl_semi_sync_master_timeout = 1000

从库配置

-- 1. 安装半同步插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

-- 2. 启用半同步
SET GLOBAL rpl_semi_sync_slave_enabled = 1;

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

-- 4. 持久化配置(写入 my.cnf)
-- [mysqld]
-- rpl_semi_sync_slave_enabled = 1

验证半同步状态

-- 主库查看
SHOW STATUS LIKE 'Rpl_semi_sync_master_status';
-- 应该返回 ON

SHOW STATUS LIKE 'Rpl_semi_sync_master_clients';
-- 显示连接的半同步从库数量

SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';
-- 显示半同步成功的事务数

SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx';
-- 显示降级为异步的事务数

-- 从库查看
SHOW STATUS LIKE 'Rpl_semi_sync_slave_status';
-- 应该返回 ON

半同步复制的注意事项

  1. 性能影响
    • 每个事务需要等待从库确认,会增加延迟
    • 通常增加 1-10ms 的延迟
    • 对高并发写入场景影响较大
  2. 超时降级
    • 如果从库响应超时,自动降级为异步复制
    • 从库恢复后自动升级回半同步
    • 需要监控降级次数
  3. 网络要求
    • 主从之间网络要稳定
    • 建议在同一机房或专线连接
    • 跨地域部署不建议使用半同步
  4. 从库数量
    • 可以配置需要多少个从库确认
    • 建议至少 1 个,最多 2-3 个
    • 过多会严重影响性能

总结

MySQL 主从复制是构建高可用数据库架构的基础技术。通过本文的学习,你应该掌握了: ✅ 主从复制的工作原理和应用场景
✅ 从零开始配置主从复制的完整步骤
✅ 常见问题的排查和解决方法
✅ 半同步复制等高级配置 在实际生产环境中,建议结合 MHA(Master High Availability)或 Orchestrator 等工具实现自动故障切换,进一步提升数据库的可用性。

参考资料