前言
MySQL主从复制,听起来可能有些技术门槛,但本质上可以理解为让多个数据库节点“共享大脑”——主库负责决策,从库负责执行。其核心是通过日志传输与重放机制,确保数据在多个节点间保持一致。本文将从最基础的原理出发,逐步带领大家完成基础主从复制配置、新增从库部署、启用GTID模式,以及搭建环形复制拓扑,全面覆盖从单主单从到多节点环形同步的完整实操流程。

一、MySQL复制核心原理与基础知识点
先别急着动手配置,磨刀不误砍柴工。深刻理解MySQL复制的核心概念与关键知识点,后续操作才能更加得心应手。
1. 复制核心架构与模式
MySQL默认采用异步复制模式。主库将数据变更写入二进制日志(Binary Log),从库则依赖两个专用线程完成同步:
- IO_THREAD:从库专属线程,主动连接主库,拉取二进制日志并存储到本地中继日志(Relay Log)中;
- SQL_THREAD:同样是从库线程,负责读取中继日志并执行其中的SQL语句,通过“重放”操作确保主从数据最终一致。
2. 复制核心配置要求
- server-id:集群中每个MySQL节点必须拥有唯一的服务器ID,这是识别节点身份的关键标识,严禁重复;
- 二进制日志:主库必须启用
log-bin,所有数据变更均需记录,这是复制的数据源; - 中继日志:从库需开启
relay-log,用于暂存从主库拉取的日志内容; - 复制用户:主库需创建具备
REPLICATION SLAVE权限的专用用户,从库拉取日志时使用该用户进行认证。
3. 复制关键特性与注意事项
- 主库理论上可挂载任意数量的从库,但生产环境建议控制在30个以内,避免主库负载过高;
- 从库的MySQL版本最好不低于主库,虽然向下兼容可行,但可能因日志解析差异导致异常;
- 从库无需持续连接主库,断开后重新连接时,会从上次同步的位置继续执行;
- 基于语句的复制(SBR)存在陷阱——像
RAND()、UUID()、NOW()这类非确定性函数,主从执行结果可能不同,因此更推荐使用基于行的复制(RBR)。
4. 复制的典型应用场景
- 横向扩展:多个从库分担读请求,实现读写分离,大幅提升整体读性能;
- 高可用性:主库一旦故障,从库可立即接管,最大限度缩短业务中断时间;
- 数据分析:将离线统计、报表查询等任务交给从库,避免影响主库的正常业务。
二、基础环境准备:MySQL多实例配置
本次实操在单台服务器上部署四个MySQL实例(server1/server2/server3/server4,端口3311-3314),模拟多节点复制集群。核心步骤包括实例配置、服务管理以及核心参数配置。
1. 停止默认MySQL服务
# 停掉系统默认的mysqld服务 systemctl stop mysqld # 确认服务已经停了 systemctl status mysqld
2. 配置MySQL多实例基础参数
创建多实例配置文件,明确每个实例的端口、数据目录、套接字文件等基础参数:
cat > /Labs/multi.cnf << 'EOF' [mysqld@server1] user=mysql socket=/mysql/server1.sock port=3311 datadir=/mysql/data1 log-error=/mysql/server1.err mysqlx=OFF [mysqld@server2] user=mysql socket=/mysql/server2.sock port=3312 datadir=/mysql/data2 log-error=/mysql/server2.err mysqlx=OFF [mysqld@server3] user=mysql socket=/mysql/server3.sock port=3313 datadir=/mysql/data3 log-error=/mysql/server3.err mysqlx=OFF [mysqld@server4] user=mysql socket=/mysql/server4.sock port=3314 datadir=/mysql/data4 log-error=/mysql/server4.err mysqlx=OFF EOF
3. 配置复制核心参数
接着编辑复制专用配置文件/labs/repl.cnf,开启二进制日志、中继日志,为每个实例分配唯一的server-id,并同时启用GTID模式(后续会用到):
# server1 核心配置 [mysqld@server1] server-id=11 log-bin=server1-bin relay-log=server1-relay-bin gtid-mode=ON enforce-gtid-consistency=ON # server2 核心配置 [mysqld@server2] server-id=12 log-bin=server2-bin relay-log=server2-relay-bin gtid-mode=ON enforce-gtid-consistency=ON # server3 核心配置 [mysqld@server3] server-id=13 log-bin=server3-bin relay-log=server3-relay-bin gtid-mode=ON enforce-gtid-consistency=ON # server4 核心配置 [mysqld@server4] server-id=14 log-bin=server4-bin relay-log=server4-relay-bin gtid-mode=ON enforce-gtid-consistency=ON
4. 启动MySQL多实例
通过系统服务管理多实例,先重新加载服务配置,再启动所有实例:
# 编辑多实例服务配置(根据实际需要调整) vim /usr/lib/systemd/system/mysqld@.service # 重新加载系统服务 systemctl daemon-reload # 启动所有MySQL实例 systemctl start mysqld@server1 systemctl start mysqld@server2 systemctl start mysqld@server3 systemctl start mysqld@server4
注意:所有实例通过
--defaults-file=/labs/repl.cnf --defaults-group-suffix=@serverX启动,会分别加载它们自己的配置。
三、实操一:基础主从复制配置(server1→server2)
首先实现一个最简单的单主单从拓扑:server1(3311)作为主库,server2(3312)作为从库。核心步骤包括主库配置、从库配置、启动复制及验证。
1. 主库(server1)配置
(1)登录主库并设置提示符
mysql -uroot -h127.0.0.1 -P3311 # 把提示符改成1>,方便区分哪个节点 1> PROMPT 1>;
(2)查看主库二进制日志位点
记录日志文件名和位置,作为从库同步的起点:
1> SHOW MASTER STATUS\G # 关键输出 # File: server1-bin.000001 -- 这是二进制日志文件名 # Position: 155 -- 这是日志写到的位置 # Executed_Gtid_Set: -- 没开启GTID的时候这里是空的
(3)创建并授权复制专用用户
创建名为repl的用户,赋予REPLICATION SLAVE权限,这里先限制从本地访问(生产环境建议限制到从库的IP):
1> CREATE USER 'repl'@'127.0.0.1' IDENTIFIED WITH mysql_native_password BY 'oracle'; 1> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'127.0.0.1'; 1> FLUSH PRIVILEGES;
(4)主库导入测试数据
创建业务库并导入数据,用于验证同步效果:
1> SOURCE /path/to/world.sql; # 导入world测试库 1> SHOW DATABASES; # 确认数据库已经创建成功
2. 从库(server2)配置
(1)登录从库并设置提示符
mysql -uroot -h127.0.0.1 -P3312 2> PROMPT 2>;
(2)配置主从复制参数
告知从库主库的地址、端口以及同步起始的日志文件和位置,必须与刚才SHOW MASTER STATUS的输出一致:
2> CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3311, MASTER_LOG_FILE='server1-bin.000001', MASTER_LOG_POS=155;
(3)启动从库复制线程
启动IO_THREAD和SQL_THREAD,从库开始拉取日志并重放:
2> START SLAVE USER='repl' PASSWORD='oracle';
3. 主从复制状态验证
(1)主库验证复制连接
在主库执行SHOW PROCESSLIST,检查是否有从库的Binlog Dump连接:
1> SHOW PROCESSLIST\G # 关键输出:State 是 Master has sent all binlog to slave; waiting for more updates
(2)从库验证复制线程状态
从库也执行SHOW PROCESSLIST,确认IO和SQL线程均正常运行:
2> SHOW PROCESSLIST\G # 关键输出:State 是 Slave has read all relay log; waiting for more updates
(3)验证数据同步结果
检查从库是否已同步world数据库,数据是否一致:
# 在主库查看数据 1> SELECT ID, Name FROM world.city ORDER BY ID DESC LIMIT 5; # 从库上查询,数据一致则说明同步成功 2> SHOW DATABASES; # 应该能看到world库 2> SELECT ID, Name FROM world.city ORDER BY ID DESC LIMIT 5;
四、实操二:新增从库部署(基于server2新增server3从库)
在现有主从拓扑(server1→server2)基础上,将server3加入作为server2的从库。其中最关键的是从库数据初始化和同步位点获取,必须通过备份确保数据一致性。
1. 从库(server2)全量备份
在server2上使用mysqldump执行备份,加上--master-data=2参数,可记录当前同步位点。此处仅备份world库:
mysqldump -uroot -h127.0.0.1 -P3312 --master-data=2 -B world > /tmp/server2.sql
注意:
--master-data=2会在备份文件中以注释形式记录当前二进制日志位点。-B指定备份的数据库,此备份仅包含world库,不包含mysql系统库中的复制用户信息。
2. 查看备份文件中的同步位点
打开备份文件,找到CHANGE MASTER TO注释行,记录日志文件名和位置:
vim /tmp/server2.sql # 关键注释行,记录了同步起始位点 # -- CHANGE MASTER TO MASTER_LOG_FILE='server2-bin.000001', MASTER_LOG_POS=736159;
3. 新从库(server3)配置
(1)登录server3并设置提示符
mysql -uroot -h127.0.0.1 -P3313 3> PROMPT 3>;
(2)导入备份文件初始化数据
将server2的world库数据恢复到server3,确保新从库的数据基础与主库一致:
3> SOURCE /tmp/server2.sql;
(3)配置复制参数并启动复制
基于备份文件中的位点,将主库设为server2,然后启动复制:
# 配置复制参数 3> CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3312, MASTER_LOG_FILE='server2-bin.000001', MASTER_LOG_POS=736159; # 启动复制线程 3> START SLAVE USER='repl' PASSWORD='oracle';
4. 新增从库同步验证
(1)验证从库复制状态
3> SHOW SLAVE STATUS\G # 关键输出:Slave_IO_Running=Yes、Slave_SQL_Running=Yes
(2)验证多级数据同步
在主库server1上修改数据,观察server2和server3是否都能同步:
# 主库server1删除数据 1> DELETE FROM world.city WHERE ID>4070; # 在server2上确认数据已删除 2> SELECT ID, Name FROM world.city ORDER BY ID DESC LIMIT 5; # 在server3上确认数据也已删除,与server2一致 3> SELECT ID, Name FROM world.city ORDER BY ID DESC LIMIT 5;
五、实操三:开启GTID并配置环形复制(server1→server2→server3→server1)
GTID(全局事务标识符)为每个事务分配唯一ID,替代传统的“文件+位点”同步方式。其优势在于自动定位同步位点,简化复制配置与故障切换。在此基础上,我们搭建一个环形复制拓扑,实现多节点互相同步。
1. 开启GTID模式(所有节点)
(1)停止所有MySQL实例与复制线程
# 停掉所有MySQL多实例 systemctl stop mysqld@server* # 登录到每个节点,停掉复制线程 1> STOP SLAVE; 2> STOP SLAVE; 3> STOP SLAVE;
(2)确认GTID配置已生效
检查/labs/repl.cnf是否已包含以下GTID核心参数(实操二中已配置):
gtid-mode=ON enforce-gtid-consistency=ON # 强制GTID一致性,防止非GTID事务出现
(3)重启所有MySQL实例
systemctl start mysqld@server1 systemctl start mysqld@server2 systemctl start mysqld@server3
2. 传统复制升级为GTID复制(server1→server2)
将基于“文件+位点”的复制升级为GTID复制,关键步骤是清空旧日志历史和开启自动定位。
(1)登录从库server2,重置主库并配置GTID同步
2> STOP SLAVE; # 停掉传统复制线程 2> RESET MASTER; # 清空旧的二进制日志和GTID历史 2> CHANGE MASTER TO MASTER_AUTO_POSITION=1; # 开启GTID自动定位 2> START SLAVE USER='repl' PASSWORD='oracle'; # 启动GTID复制
(2)验证GTID复制状态
2> SHOW SLAVE STATUS\G # 关键输出:Master_Auto_Position=1、Slave_IO_Running=Yes、Slave_SQL_Running=Yes
3. 搭建GTID模式环形复制拓扑
配置环形复制:server1→server2→server3→server1。所有节点既为主库也为从库,核心是每个节点指定一个上游主库,并开启GTID自动定位。
(1)配置server2→server3的GTID复制
# 登录server3,停掉旧的复制并重置 3> STOP SLAVE; 3> RESET MASTER; # 将主库设为server2,开启GTID自动定位 3> CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3312, MASTER_AUTO_POSITION=1; # 启动复制 3> START SLAVE USER='repl' PASSWORD='oracle';
(2)配置server3→server1的GTID复制
# 登录server1,停掉旧的复制并重置 1> STOP SLAVE; 1> RESET MASTER; # 将主库设为server3,开启GTID自动定位 1> CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3313, MASTER_AUTO_POSITION=1; # 启动复制 1> START SLAVE USER='repl' PASSWORD='oracle';
4. 环形复制状态与数据同步验证
(1)各节点验证GTID复制状态
每个节点执行SHOW SLAVE STATUS\G,确认Slave_IO_Running=Yes、Slave_SQL_Running=Yes、Master_Auto_Position=1。
(2)验证环形数据同步
在任意节点修改数据,检查其他节点是否同步,环形通路是否正常:
# 在server2上插入/更新数据
2> INSERT INTO world.city (Name, CountryCode, District, Population) VALUES ('TestCity', 'USA', 'California', 10000);
# 在server3上确认数据已同步
3> SELECT * FROM world.city WHERE Name='TestCity';
# 在server1上确认数据也已同步
1> SELECT * FROM world.city WHERE Name='TestCity';
(3)查看节点GTID与UUID
# 查看节点UUID,GTID集群中靠此唯一标识节点 2> SELECT @@server_uuid; # 查看已执行过的GTID事务 2> SHOW MASTER STATUS\G;
六、实操常见问题与解答
1. 备份文件中为什么没有复制用户repl?
因为mysqldump备份时使用了-B world,仅指定了业务库world。而复制用户repl存储在mysql系统库中,因此未被包含在备份文件中。实际上,复制用户是在主库创建后通过复制同步到从库,而非通过备份文件传递。
2. 从库启动后Slave_IO_Running=No怎么排查?
- 检查主从库的
server-id是否唯一,有无重复; - 验证复制用户的密码是否正确,权限是否为
REPLICATION SLAVE; - 检查主库二进制日志是否已开启(
log-bin); - 确认主从库之间的网络连通性,防火墙是否开放了相应端口;
- 验证从库配置的
MASTER_LOG_FILE和MASTER_LOG_POS是否与主库一致。
3. GTID模式与传统复制模式的核心区别是什么?
- 传统复制:依赖“二进制日志文件 + 位点”确定同步起点,需手动记录和配置,故障切换后需重新定位;
- GTID复制:通过全局唯一的事务ID定位,无需手动指定文件和位点,通过
MASTER_AUTO_POSITION=1实现自动定位,配置和故障切换更加简便,复制可靠性更高。
七、核心知识点总结
- MySQL异步复制的核心是二进制日志 + 中继日志,依靠IO_THREAD和SQL_THREAD两个线程实现主从同步。集群中
server-id唯一是前提条件; - 基础主从复制的关键步骤清晰:主库开启binlog并创建复制用户→记录主库位点→从库配置参数→启动复制线程→验证同步;
- 新增从库时,使用
mysqldump --master-data=2进行数据初始化 + 同步位点记录,确保新从库数据基础与主库一致; - GTID通过全局唯一事务ID替代传统的“文件+位点”,实现自动定位同步位点。核心配置为
gtid-mode=ON加上MASTER_AUTO_POSITION=1; - 环形复制是多节点互为主从的拓扑模式,必须基于GTID实现,适合多区域数据同步。配置核心是每个节点指定一个上游主库并开启GTID自动定位;
- 验证复制的标准:从库的
Slave_IO_Running=Yes、Slave_SQL_Running=Yes,且各节点数据完全一致。
