MySQL 主从复制与 GTID 环形复制

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>,标识从库
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 库数据,保证新从库与主库数据基础一致:

复制代码
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(Global Transaction Identifier,全局事务标识符)为每个事务分配唯一标识,替代传统的「文件 + 位点」同步方式,实现自动定位同步位点 ,简化复制配置与故障切换。在此基础上搭建环形复制,实现多节点互相同步。

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=YesSlave_SQL_Running=YesMaster_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如何排查?

  1. 检查主从库server-id是否唯一,无重复;
  2. 验证复制用户密码是否正确,权限是否为REPLICATION SLAVE
  3. 检查主库二进制日志是否开启(log-bin);
  4. 验证主从库网络连通性,端口是否开放;
  5. 检查从库配置的MASTER_LOG_FILEMASTER_LOG_POS是否与主库一致。

3. GTID 模式与传统复制模式的核心区别?

  • 传统复制:基于「二进制日志文件 + 位点」定位同步起始点,需手动记录和配置,故障切换时需重新查找位点;
  • GTID 复制:基于全局唯一事务 ID 定位,无需手动指定文件和位点,通过MASTER_AUTO_POSITION=1实现自动定位,简化配置与故障切换,提升复制可靠性。

七、核心知识点总结

  1. MySQL 异步复制的核心是二进制日志 + 中继日志 ,通过 IO_THREAD 和 SQL_THREAD 实现主从数据同步,server-id唯一是集群配置的前提;
  2. 基础主从复制配置的核心步骤为:主库开启 binlog + 创建复制用户→记录主库位点→从库配置参数→启动复制线程→验证同步;
  3. 新增从库时,需通过mysqldump --master-data=2实现数据初始化 + 同步位点记录,保证新从库与主库数据基础一致;
  4. GTID 通过全局唯一事务 ID 替代传统「文件 + 位点」,实现自动定位同步位点,核心配置为gtid-mode=ON+MASTER_AUTO_POSITION=1
  5. 环形复制是多节点互为主从的拓扑模式,需基于 GTID 实现,适用于多区域数据同步场景,配置核心为每个节点指定上游主库并开启 GTID 自动定位;
  6. 复制验证的核心标准为:从库Slave_IO_Running=YesSlave_SQL_Running=Yes,且各节点数据完全一致。
相关推荐
白太岁1 小时前
C++:(6) 常用 linux 命令:进程管理、日志查看、网络端口与文件权限
linux·运维·服务器
“αβ”1 小时前
MySQL数据类型
c语言·数据库·opencv·mysql·数据挖掘·数据类型·数据
MMME~2 小时前
HAProxy:高性能负载均衡实战指南
linux·运维·数据库
sryyd_022 小时前
云原生-高可用集群keepalived
服务器·网络·云原生
野指针YZZ2 小时前
Gstreamer插入第三方plugins流程:rgaconvert
linux·音视频·rk3588
快快起来写代码2 小时前
Arrays.asList方法踩坑
linux
济6172 小时前
ARM Linux 驱动开发篇--- pinctrl 子系统详解-- Ubuntu20.04
linux·嵌入式·嵌入式linux驱动开发
云飞云共享云桌面2 小时前
10人SolidWorks设计团队如何提升SolidWorks软件利用率
大数据·linux·运维·服务器·网络·人工智能
czxyvX5 小时前
019-Linux-Socket编程-TCP
linux·tcp/ip