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 线程的工作流程:
- 从库 IO 线程连接到主库
- 主库创建一个 binlog dump 线程
- dump 线程读取 binlog 并发送给从库
- 从库 IO 线程接收数据并写入 Relay Log
3. 从库重放日志
从库的 SQL 线程 读取 Relay Log,并在从库上重新执行这些 SQL 语句,从而实现数据同步。
SQL 线程的工作流程:
- SQL 线程读取 Relay Log 中的事件
- 解析事件并转换为 SQL 语句
- 在从库上执行这些 SQL 语句
- 更新复制位置信息

复制的关键概念
1. 复制位置(Position)
- 主库的 binlog 文件名和位置
- 从库记录已经复制到的位置
- 用于断点续传,从库重启后从上次位置继续
2. 复制延迟
- 主库执行完成到从库执行完成的时间差
- 通过
Seconds_Behind_Master查看 - 延迟过大会影响读写分离的数据一致性
3. 复制过滤
- 可以指定只复制某些数据库或表
- 使用
binlog-do-db和replicate-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,... | |
+------------------+----------+--------------+------------------+-------------------+
重要:记住 File 和 Position 的值!
步骤 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)
- 网络带宽限制或网络延迟高
- 从库上有其他查询占用资源
- 大事务导致的延迟(如一次性插入大量数据)
解决方案:
- 使用并行复制(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;
- 优化从库硬件
- 使用 SSD 硬盘提升 IO 性能
- 增加内存,提高缓存命中率
- 升级 CPU,提升处理能力
- 优化主库写入
- 批量操作改为小批量多次
- 避免大事务,拆分为小事务
- 优化索引,减少写入时间
- 使用半同步复制
-- 主库启用半同步
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_Running 或 Slave_SQL_Running 为 No
排查步骤:
-- 查看详细错误信息
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-10ms 的延迟
- 对高并发写入场景影响较大
- 超时降级:
- 如果从库响应超时,自动降级为异步复制
- 从库恢复后自动升级回半同步
- 需要监控降级次数
- 网络要求:
- 主从之间网络要稳定
- 建议在同一机房或专线连接
- 跨地域部署不建议使用半同步
- 从库数量:
- 可以配置需要多少个从库确认
- 建议至少 1 个,最多 2-3 个
- 过多会严重影响性能
总结
MySQL 主从复制是构建高可用数据库架构的基础技术。通过本文的学习,你应该掌握了:
✅ 主从复制的工作原理和应用场景
✅ 从零开始配置主从复制的完整步骤
✅ 常见问题的排查和解决方法
✅ 半同步复制等高级配置
在实际生产环境中,建议结合 MHA(Master High Availability)或 Orchestrator 等工具实现自动故障切换,进一步提升数据库的可用性。