MySQL主从复制详解
前言
在现代数据库架构中,高可用性、负载均衡和数据备份是至关重要的考量因素。MySQL 的主从复制(Replication)机制正是解决这些问题的核心技术之一。通过主从复制,我们可以将主数据库(Master)的数据变更实时同步到一个或多个从数据库(Slave),从而实现读写分离以提升性能,或者作为热备份以保障数据安全和业务连续性。
本文将详细介绍两种主流的 MySQL 主从复制搭建方式:
基于二进制日志位置点(Position-based)的传统复制
基于全局事务标识符(GTID)的现代复制
我们将从原理入手,结合清晰的架构图和详细的命令行步骤,带您一步步完成两种模式下的主从集群搭建。
核心复制原理
在深入具体操作之前,我们先通过下面这张图来理解 MySQL 主从复制的基本工作流程:

整个复制过程主要由三个线程协同完成:
Master 端的 Binlog Dump 线程:当从库连接主库时,主库会创建一个 binlog dump 线程。该线程负责读取主库的二进制日志(binlog)中的事件,并将其发送给从库。
Slave 端的 I/O 线程:从库的 I/O 线程负责连接到主库,接收 binlog dump 线程发送过来的 binlog 事件,并将其写入到从库本地的中继日志(Relay Log)中。
Slave 端的 SQL 线程:从库的 SQL 线程负责读取中继日志(Relay Log)中的事件,并将其在从库上重放(Replay),从而实现数据的最终同步。
详细流程拆解(对应图中序号):
从库执行 start slave 命令,启动复制流程。
I/O 线程读取 master.info 文件中记录的主库连接信息,并连接到主库。
连接成功后,I/O 线程向主库发送请求,索要指定 binlog 文件和位置点(Position)之后的日志事件。
主库收到请求后,binlog dump 线程开始从 binlog 文件中读取事件。
binlog dump 线程将读取到的事件发送给从库的 I/O 线程。
I/O 线程接收事件并将其写入本地的 Relay Log。
同时,I/O 线程会更新 master.info 文件,记录已同步到的 binlog 文件名和位置点。
SQL 线程读取 relay-log.info 文件,获取上次重放到的中继日志位置。
SQL 线程从该位置开始读取 Relay Log 中的事件并执行。
执行后的 SQL 语句会应用到从库的数据库中,实现数据同步。
方式一:基于位置点进行主从同步
这是最传统和经典的主从复制方式,其核心是精确地告诉从库应该从主库的哪个 binlog 文件的哪个位置开始复制。
步骤一:创建主数据库
(此处省略主库的安装和基础配置过程)
步骤二:创建从数据库并配置
(此处省略主库的安装和基础配置过程)
1.编写从库配置文件:确保从库的 server_id 与主库不同。
# [root@db02 ~]# cat /etc/my.cnf
[mysqld]
server_id=2 # 不能和主库的 server_id 数值一致2.重启数据库使配置生效。
# [root@db02 /backup]# /etc/init.d/mysqld restart
Shutting down MySQL.... SUCCESS!
Starting MySQL.. SUCCESS!步骤三:在主库上进行数据备份
为了保证主从数据在初始状态的一致性,我们需要对主库进行一次全量备份。
# [root@db01 ~]# mysqldump -uroot -p123456 -A --source-data --single-transaction > /backup/all.sql--source-data (或 --master-data): 会在备份文件的开头自动记录备份结束时刻的 binlog 文件和位置点信息,这对于后续建立主从关系至关重要。
--single-transaction: 使用事务模式进行备份,对于 InnoDB 存储引擎可以实现不锁表的热备。
备份完成后,查看备份文件头部,可以看到类似信息:
-- [root@db02 ~]# head -30 /backup/all.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='binlog.000001', MASTER_LOG_POS=21104605;步骤四:在主库上创建同步用户并授权
创建一个专门用于主从同步的数据库用户,并授予 REPLICATION SLAVE 权限。
-- 在主库上执行
mysql> CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';步骤五:在从库上恢复数据
将备份文件从主库传输到从库。
# [root@db01 ~]# scp -rp /backup/all.sql 10.1.12.15:/backup/
在从库上导入数据
[root@db02 ~]#mysql -uroot </backup/all.sql步骤六:在从库上配置并启动主从同步
使用备份文件中记录的 binlog 信息来配置主从关系。
-- 在从库上执行
mysql> CHANGE MASTER TO
-> MASTER_HOST='10.1.12.4',
-> MASTER_PORT=3306,
-> MASTER_USER='repl',
-> MASTER_PASSWORD='123456',
-> MASTER_LOG_FILE='binlog.000001',
-> MASTER_LOG_POS=21104605; -- 此处使用备份文件中记录的位置点注意:MASTER_LOG_FILE 和 MASTER_LOG_POS 的值应以来源于 mysqldump 备份文件中的 CHANGE MASTER TO 注释行,或在主库上执行 SHOW MASTER STATUS; 获取当前最新的位置点。
激活主从同步:
mysql> START SLAVE;检查主从状态:
mysql> SHOW SLAVE STATUS\G;
可以看到 Slave_IO_Running: Yes 和 Slave_SQL_Running: Yes,则表示主从同步已成功建立。
创建数据库测试

方式二:GTID 同步复制
GTID (Global Transaction ID) 是 MySQL 5.6 版本引入的新特性,它为每一个已提交的事务分配一个全局唯一的ID。使用 GTID 进行复制,不再需要关心具体的 binlog 文件名和位置点,极大地简化了故障转移和主从切换的过程。
复制原理机制:
Master:在更新数据时,会在事务前生成一个 GTID,并将其与事务一起记录到 binlog 中。
Slave:
I/O 线程像往常一样拉取 binlog 并写入 Relay Log。
SQL 线程从 Relay Log 中读取到 GTID。
SQL 线程会检查这个 GTID 是否已经在从库上执行过(通过查询从库自身的 binlog 或 gtid_executed 系统变量)。
如果该 GTID 已存在,说明事务已被执行,则直接跳过。
如果该 GTID 不存在,则执行该事务,并将此 GTID 记录下来。
实现步骤:
步骤一:配置主数据库
修改主库配置文件 my.cnf,开启 GTID 相关功能。
# [root@db01 /usr/local]# cat /etc/my.cnf
[mysqld]
...
gtid-mode=on
enforce-gtid-consistency=true # 强制GTID一致性,确保只有安全的语句能被记录
log-slave-updates=1 # 建议开启,使从库也能记录从主库同步过来的事务日志重启数据库使配置生效。
步骤二:创建从数据库
修改从库配置文件,与主库一样,开启 GTID 功能。
# [root@db03 /usr/local]# cat /etc/my.cnf
[mysqld]
server_id=3
...
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1初始化并启动从库
[root@db03 ~]#mysqld --initialize-insecure --datadir=/data/3306/data --basedir=/usr/local/mysql/ --user=mysql
启动数据库:
[root@db03 ~]#/etc/init.d/mysqld start
Starting MySQL.Logging to '/data/3306/data/db03.err'.
........... SUCCESS! 同样,进行数据备份、传输和恢复(同方式一的步骤三、五)。
步骤三:建立主从同步
这是 GTID 模式与位置点模式最核心的区别。
-- 在从库上执行
mysql> CHANGE MASTER TO
-> MASTER_HOST='10.1.12.4',
-> MASTER_PORT=3306,
-> MASTER_USER='repl',
-> MASTER_PASSWORD='123456',
-> MASTER_AUTO_POSITION=1; -- 关键参数!表示启用GTID自动定位MASTER_AUTO_POSITION=1 参数告诉从库:你不需要关心 binlog 文件和位置点,自己去和主库协商,找到你还没执行过的事务(GTID)并开始同步。
启动同步:
mysql> START SLAVE;验证:
在主库上创建一个新数据库,然后在从库上查看。
在主库或从库上查看 master status,可以看到 Executed_Gtid_Set 字段,它记录了所有已执行的事务ID。当主库有新的写入时,这个集合会增长,从库也会很快跟上。
主库状态示例:
mysql> show master status;
+---------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+------------------------------------------+
| binlog.000001 | 157 | | | ac970576-4a4b-11f0-90d2-000c29dc5c04:1-2 |
+---------------+----------+--------------+------------------+------------------------------------------+从库很快也会达到同样的状态。
mysql> show master status;
+---------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+------------------------------------------+
| binlog.000001 | 157 | | | ac970576-4a4b-11f0-90d2-000c29dc5c04:1-2 |
+---------------+----------+--------------+------------------+------------------------------------------+总结
位置点复制:是经典、基础的复制方式。优点是兼容性好,所有版本都支持;缺点是在主库发生故障切换时,手动寻找新主库的正确同步点较为繁琐,容易出错。
GTID 复制:是 MySQL 5.6+ 推荐的现代复制方式。其最大优势在于 MASTER_AUTO_POSITION,它让主从同步和故障转移变得极其简单和可靠,从库可以自动找到正确的同步点。