游乐游手机版
首页/数据库/文章详情

MySQL主从复制与GTID环形复制代码实例

时间:2026-07-20 07:00
MySQL主从复制通过二进制日志和中继日志实现数据同步,支持异步复制与GTID自动定位。实操涵盖多实例配置、基础主从复制、新增从库部署及环形复制拓扑搭建,实现多节点数据一致与高可用扩展。

前言

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> 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=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,且各节点数据完全一致。
来源:https://www.jb51.net/database/367204jae.htm
上一篇MySQL连接查询:内连接、外连接与复合条件详解 下一篇MySQL 5.7到8迁移:GROUP BY差异与优化建议
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
为什么SQL中 NOT IN 子查询遇到 NULL 会导致 JOIN 逻辑完全崩溃失效
数据库 · 2026-07-21

为什么SQL中 NOT IN 子查询遇到 NULL 会导致 JOIN 逻辑完全崩溃失效

SQL的NOTIN子查询若结果包含NULL,三值逻辑会使整行判断为UNKNOWN,WHERE仅保留TRUE,导致所有行被过滤,返回空集。推荐使用NOTEXISTS替代,它不比较值,只判断子查询是否返回行,天然规避NULL问题。LEFTJOIN+ISNULL易写错,COALESCE或加ISNOTNULL仅权宜之计,可能掩盖数据问题。

完整Redis集群架构图及搭建步骤详解,新手必看
数据库 · 2026-07-21

完整Redis集群架构图及搭建步骤详解,新手必看

一、简介 Redis集群功能从3 0版本开始引入,到5 0 14版本已经相当成熟。本文就来聊聊如何搭建一个最简单的集群,以及常用的集群管理命令。版本锁定在5 0 14,所有操作均基于此版本。 二、架构图 先来看一个最基础的集群架构,一目了然: 三、搭建集群 3 1、下载 这里是在一台Linux服务器

SQL存储过程结合XML数据类型的高性能解析技巧
数据库 · 2026-07-21

SQL存储过程结合XML数据类型的高性能解析技巧

直接用 nodes() + value(),别碰 OPENXML 从 SQL Server 2005 起,OPENXML 就应该被淘汰了。它需要手动调用 sp_xml_preparedocument 和 sp_xml_removedocument,一旦遗漏后者就会引发内存泄漏;而且整个过程基于临

SQL窗口函数生成带层级结构的财务流水号技巧
数据库 · 2026-07-21

SQL窗口函数生成带层级结构的财务流水号技巧

财务流水号按业务类型分组连续编号,需用ROW_NUMBER()OVER(PARTITIONBYbusiness_typeORDERBYcreate_time)生成,避免先GROUPBY致明细丢失。日期前缀和补零拼接需注意数据库差异。多级嵌套结构需在PARTITIONBY中增加额外分类字段,并发环境下窗口函数无法保证唯一性,需结合序列或锁机制。

SQL中COALESCE函数优雅处理NULL值技巧与最佳实践全面指南
数据库 · 2026-07-21

SQL中COALESCE函数优雅处理NULL值技巧与最佳实践全面指南

COALESCE函数从左到右返回首个非NULL值,参数顺序决定兜底是否生效;类型不兼容时PostgreSQL和SQLServer报错,需显式CAST对齐;运算前需对每个可能为NULL的项单独包裹,否则表达式整体为NULL;避免在WHERE或JOIN条件中使用,否则导致语义错乱或索引失效;不处理空字符串,需嵌套NULLIF。