Loading

MySQL 8.0主从复制原理与流程

MySQL 8.0 主从复制原理与流程

1. 基本概念

1.1 什么是主从复制

MySQL主从复制(Replication)是官方提供的主从同步方案,用于将一个MySQL实例的数据同步到另一个实例中。这是使用最广泛的容灾方案。

1.2 复制的优势

  • 高可用性:通过配置一定的复制机制,MySQL实现了跨主机的数据复制,从而获得一定的高可用能力。
  • 性能扩展:通过配置一个或多个副本,将读请求分发至副本节点,从而获得整体上读写性能的提升。
  • 异地灾备:只需要将副本节点部署到异地机房,就可以轻松获得一定的异地灾备能力。

1.3 复制的缺点

  • 没有故障自动转移,容易造成单点故障
  • 主库从库之间有主从复制延迟问题,容易造成最终数据的不一致
  • 从库过多对主库的负载以及网络带宽都会带来很大的负担

2. 应用场景

  • 电子商务平台:实现读写分离,提高并发处理能力
  • 社交网络:提供快速的读取服务
  • 实时监控和报警系统:实现数据的分布式存储和快速数据查询
  • 新闻和媒体网站:提供高可用性和快速的内容访问
  • 金融服务:数据备份和高可用性的实现

3. 复制方式

3.1 基于二进制日志(binlog)的复制

传统的方法是基于从源的二进制日志(binlog)复制事件,并要求日志文件及其中的位置在源和副本之间进行同步。

3.2 基于全局事务标识符(GTID)的复制

基于GTID的复制是完全基于事务的,所以很容易确定源和副本是否一致;只要在源上提交的所有事务也在副本上提交,就可以保证两者之间的一致性。

4. 数据同步类型

4.1 异步复制

默认情况下,MySQL采用异步复制的方式,执行事务操作的线程不会等复制Binlog的线程。

4.2 半同步复制

在MySQL 5.7版本开始,增加一种半同步复制(Semisynchronous Replication)的方式。主节点在收到客户端的请求后,必须在完成本节点日志写入的同时,还需要等待至少一个从节点完成数据同步的响应之后(或超时),才会响应请求。

4.3 延迟复制

MySQL 8.0还支持延迟复制,以使副本故意落后于源至少指定的时间。

5. 复制原理

5.1 异步复制原理

  1. 主库在收到客户端提交事务的请求之后,会先写入Binlog,然后再提交事务,更新存储引擎中的数据。
  2. 从库会有一个专门的复制线程,从主库接收Binlog,然后把Binlog写到一个中继日志里面。
  3. 从库还有另外一个回放Binlog的线程,去读中继日志,然后回放Binlog更新存储引擎中的数据。

5.2 基于binlog位点同步的主从复制原理

  1. 主库会生成多个binlog日志文件。
  2. 从库的I/O线程请求指定文件和指定位置的binlog日志文件(位点)。
  3. 主库dump线程获取指定位点的binlog日志。
  4. 主库按照从库发送给来的位点信息读取binlog,然后推送binlog给从库。
  5. 从库将得到的binlog写到本地的relay log(中继日志)文件中。
  6. 从库的SQL线程读取和解析relay log文件。
  7. 从库的SQL线程重放relay log中的命令。

6. 实践操作

6.1 Docker环境准备

6.1.1 安装Docker

在Ubuntu/Debian系统上:

sudo apt update
sudo apt install docker.io docker-compose -y
sudo systemctl start docker
sudo systemctl enable docker

在CentOS/RHEL系统上:

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io -y
sudo systemctl start docker
sudo systemctl enable docker

6.1.2 创建Docker网络

# 创建主从复制专用网络
docker network create --driver bridge mysql-source-replica

6.2 搭建MySQL 8一主两从复制架构

6.2.1 配置主节点

  1. 创建挂载目录
# 创建主节点目录结构
mkdir -p /mysql/replication/source/data \
         /mysql/replication/source/conf \
         /mysql/replication/source/log
  1. 准备主节点配置文件
# 创建并编辑配置文件
vim /mysql/replication/source/conf/custom.cnf

配置文件内容:

[mysql]
default-character-set=utf8

[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
secure-file-priv= NULL
symbolic-links=0

# 服务器唯一ID,默认是1
server-id=10

# 启用二进制日志
log-bin=mysql-bin

# 最大连接数
max_connections=1000

# 设置默认时区
default-time_zone='+8:00'

# 0: 区分大小写
# 1: 不区分大小写
lower_case_table_names=1

!includedir /etc/mysql/conf.d/
  1. 运行主节点MySQL容器
# 启动主节点容器
docker run -d \
--name mysql-source \
--privileged=true \
--restart=always \
--network mysql-source-replica \
-p 3307:3306 \
-v /mysql/replication/source/data:/var/lib/mysql \
-v /mysql/replication/source/conf:/etc/mysql/conf.d \
-v /mysql/replication/source/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
mysql:8.0.27 \
--lower_case_table_names=1
  1. 配置主节点远程访问
# 进入主节点容器
docker exec -it mysql-source /bin/bash

# 登录MySQL
mysql -u root -p
# 输入密码: 123456

# 创建复制用户并授权
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

# 查看主节点状态
SHOW MASTER STATUS;

6.2.2 配置从节点1

  1. 创建挂载目录
# 创建从节点1目录结构
mkdir -p /mysql/replication/replica1/data \
         /mysql/replication/replica1/conf \
         /mysql/replication/replica1/log
  1. 准备从节点1配置文件
# 创建并编辑配置文件
vim /mysql/replication/replica1/conf/custom.cnf

配置文件内容:

[mysql]
default-character-set=utf8

[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
secure-file-priv= NULL
symbolic-links=0

# 服务器唯一ID,默认是1
server-id=11

# 启用二进制日志
log-bin=mysql-bin

# 最大连接数
max_connections=1000

# 设置默认时区
default-time_zone='+8:00'

# 0: 区分大小写
# 1: 不区分大小写
lower_case_table_names=1

!includedir /etc/mysql/conf.d/
  1. 运行从节点1 MySQL容器
# 启动从节点1容器
docker run -d \
--name mysql-replica1 \
--privileged=true \
--restart=always \
--network mysql-source-replica \
-p 3308:3306 \
-v /mysql/replication/replica1/data:/var/lib/mysql \
-v /mysql/replication/replica1/conf:/etc/mysql/conf.d \
-v /mysql/replication/replica1/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
mysql:8.0.27 \
--lower_case_table_names=1
  1. 配置从节点1远程访问
# 进入从节点1容器
docker exec -it mysql-replica1 /bin/bash

# 登录MySQL
mysql -u root -p
# 输入密码: 123456

# 配置主从复制关系
CHANGE MASTER TO 
MASTER_HOST='mysql-source',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=151,
MASTER_CONNECT_RETRY=10;

# 启动从节点复制
START SLAVE;

# 查看从节点状态
SHOW SLAVE STATUS\G

6.2.3 配置从节点2

从节点2的配置与从节点1类似,主要区别在于目录路径、容器名称、端口映射和server-id:

  1. 创建挂载目录
# 创建从节点2目录结构
mkdir -p /mysql/replication/replica2/data \
         /mysql/replication/replica2/conf \
         /mysql/replication/replica2/log
  1. 配置文件中的server-id改为12
  2. 容器名称改为mysql-replica2
  3. 端口映射改为-p 3309:3306

6.3 配置主从复制

6.3.1 主库配置复制用户

# 在主库中执行
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

6.3.2 查看master机器的状态

# 在主库中执行
SHOW MASTER STATUS;

记录File和Position字段的值,用于从库配置。

6.3.3 从节点设置主库信息

# 在从库中执行
CHANGE MASTER TO 
MASTER_HOST='主库IP地址',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='记录的File值',
MASTER_LOG_POS=记录的Position值,
MASTER_CONNECT_RETRY=10;

6.3.4 开启从库

# 在从库中执行
START SLAVE;
SHOW SLAVE STATUS\G

检查Slave_IO_Running和Slave_SQL_Running是否都为Yes。

6.4 半同步复制配置

6.4.1 安装半同步插件

# 在主库中执行
INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so';

# 在从库中执行
INSTALL PLUGIN rpl_semi_sync_replica SONAME 'semisync_replica.so';

6.4.2 开启半同步功能

# 在主库中执行
SET GLOBAL rpl_semi_sync_source_enabled = 1;
SET GLOBAL rpl_semi_sync_source_wait_for_replica_count = 1;

# 在从库中执行
SET GLOBAL rpl_semi_sync_replica_enabled = 1;

6.4.3 重启从节点上的I/O线程

# 在从库中执行
STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

6.4.4 半同步复制测试

# 在主库中创建测试表
USE test;
CREATE TABLE test_table (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO test_table VALUES (1, 'test');

# 在从库中验证数据是否同步
SELECT * FROM test.test_table;

6.5 复制状态监控

6.5.1 查看主库状态

# 查看二进制日志
SHOW MASTER LOGS;

# 查看主库状态
SHOW MASTER STATUS;

6.5.2 查看从库状态

# 查看从库状态
SHOW SLAVE STATUS\G

# 查看进程列表
SHOW PROCESSLIST;

6.5.3 常见状态检查

  • Slave_IO_Running: Yes - I/O线程是否运行正常
  • Slave_SQL_Running: Yes - SQL线程是否运行正常
  • Seconds_Behind_Master: 0 - 主从延迟时间
  • Last_Error: 空 - 是否有错误信息

7. GTID复制

7.1 GTID概念

GTID是一个基于原始mysql服务器生成的一个已经被成功执行的全局事务ID,它由服务器ID以及事务ID组合而成。

7.2 GTID的优势

  • 更简单的实现failover,不用以前那样在需要找位点
  • 更简单的搭建主从复制
  • 比传统的复制更加安全
  • GTID是连续的没有空洞的,保证数据的一致性,零丢失

7.3 GTID配置

7.3.1 主库GTID配置

  1. 修改主库配置文件
# 编辑主库配置文件
vim /mysql/replication/source/conf/custom.cnf

在[mysqld]部分添加以下配置:

# GTID配置
gtid_mode = on
enforce_gtid_consistency = on

# 启用二进制日志
log-bin = mysql-bin
binlog_format = row

# 服务器唯一ID
server-id = 10
  1. 重启主库容器
docker restart mysql-source
  1. 验证GTID配置
# 登录主库MySQL
mysql -u root -p

# 查看GTID相关变量
SHOW VARIABLES LIKE 'gtid_mode';
SHOW VARIABLES LIKE 'enforce_gtid_consistency';

7.3.2 从库GTID配置

  1. 修改从库配置文件
# 编辑从库配置文件
vim /mysql/replication/replica1/conf/custom.cnf

在[mysqld]部分添加以下配置:

# GTID配置
gtid_mode = on
enforce_gtid_consistency = on

# 启用二进制日志
log-bin = mysql-bin
binlog_format = row

# 服务器唯一ID
server-id = 11
  1. 重启从库容器
docker restart mysql-replica1
  1. 验证GTID配置
# 登录从库MySQL
mysql -u root -p

# 查看GTID相关变量
SHOW VARIABLES LIKE 'gtid_mode';
SHOW VARIABLES LIKE 'enforce_gtid_consistency';

7.3.3 配置基于GTID的主从复制

  1. 停止从库复制
# 在从库中执行
STOP SLAVE;
  1. 配置基于GTID的复制
# 在从库中执行
CHANGE MASTER TO 
MASTER_HOST='mysql-source',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_AUTO_POSITION = 1;
  1. 启动从库复制
# 在从库中执行
START SLAVE;
SHOW SLAVE STATUS\G

7.3.4 GTID复制状态监控

  1. 查看已执行的GTID集合
# 在主库和从库中执行
SHOW MASTER STATUS\G
SHOW SLAVE STATUS\G

# 查看GTID执行情况
SELECT * FROM mysql.gtid_executed;
  1. 查看GTID相关变量
# 查看GTID模式
SHOW VARIABLES LIKE 'gtid_mode';

# 查看GTID一致性
SHOW VARIABLES LIKE 'enforce_gtid_consistency';

# 查看已接收的GTID
SHOW STATUS LIKE 'Slave_received_heartbeats';

7.3.5 GTID复制故障处理

  1. 跳过事务
# 停止从库复制
STOP SLAVE;

# 设置要跳过的GTID
SET @@SESSION.GTID_NEXT = '已知的GTID值';

# 执行空事务跳过
BEGIN; COMMIT;

# 恢复自动GTID模式
SET @@SESSION.GTID_NEXT = AUTOMATIC;

# 启动从库复制
START SLAVE;
  1. 重置GTID
# 在从库中执行
STOP SLAVE;
RESET SLAVE ALL;

# 重新配置主从关系
CHANGE MASTER TO 
MASTER_HOST='mysql-source',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_AUTO_POSITION = 1;

START SLAVE;

8. 组复制(Group Replication)

8.1 什么是组复制

Group Replication提供了分布式状态机复制,服务器之间具有很强的协调性。当服务器属于同一组时,它们会自动进行协调。

8.2 单主模式

在单主模式下,组中只有一个主服务器,该主服务器被设置为读写模式。组中的所有其他成员都被设置为只读模式。

8.3 多主模式

在多主模式下,没有成员具有特殊的角色。任何与其他组成员兼容的成员在加入组时都被设置为读写模式,并且可以处理写事务,即使它们是并发发布的。

8.4 组复制配置

8.4.1 环境准备

  1. 创建组复制网络
# 创建组复制专用网络
docker network create --driver bridge mgr-network
  1. 创建数据目录
# 创建三个节点的数据目录
mkdir -p /mysql/mgr/node1/data /mysql/mgr/node1/conf /mysql/mgr/node1/log
mkdir -p /mysql/mgr/node2/data /mysql/mgr/node2/conf /mysql/mgr/node2/log
mkdir -p /mysql/mgr/node3/data /mysql/mgr/node3/conf /mysql/mgr/node3/log

8.4.2 配置文件准备

  1. 节点1配置文件
# 创建并编辑节点1配置文件
vim /mysql/mgr/node1/conf/custom.cnf

配置内容:

[mysql]
default-character-set=utf8

[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
secure-file-priv= NULL
symbolic-links=0

# 对于Group Replication,数据必须存储在InnoDB事务存储引擎中
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"

# 指定sever_id,三个Mysql实例需要分别改为对应的sever_id
server_id=1

# 必须开启GTID支持
gtid_mode=ON
enforce_gtid_consistency=ON

# 启用二进制日志
log-bin=mysql-bin
log-slave-updates=ON
binlog-format=ROW

# 组复制设置
# 实例启动时会将组复制插件加载到插件列表中
plugin_load_add='group_replication.so'

# 组名三个节点必须保证一致,必须是UUID,可以使用SELECT UUID()生成一个
group_replication_group_name="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"

# 插件在服务器启动时不自动启动,可以等配置好服务器之后手动启动
group_replication_start_on_boot=off

# 配置与组内其他成员通信是使用的主机名和端口,内部通讯端口,推荐使用33061
group_replication_local_address= "mgr-node1:33061"

# 设置组成员的主机名和端口
group_replication_group_seeds= "mgr-node1:33061,mgr-node2:33061,mgr-node3:33061"

# 通常会在实例运行时配置group_replication_bootstrap_group,以确保只有一个成员实际引导组
group_replication_bootstrap_group=off

# 单主模式
group_replication_single_primary_mode=ON

# 最大连接数
max_connections=10000

# 设置默认时区
default-time_zone='+8:00'

# 0: 区分大小写
# 1: 不区分大小写
lower_case_table_names=1

!includedir /etc/mysql/conf.d/
  1. 节点2和节点3配置文件
    节点2和节点3的配置文件与节点1类似,主要修改以下内容:
  • server_id分别为2和3
  • group_replication_local_address分别为mgr-node2:33061和mgr-node3:33061

8.4.3 启动容器

# 启动节点1
docker run -d \
--name mgr-node1 \
--privileged=true \
--restart=always \
--network mgr-network \
-p 3321:3306 \
-v /mysql/mgr/node1/data:/var/lib/mysql \
-v /mysql/mgr/node1/conf:/etc/mysql/conf.d \
-v /mysql/mgr/node1/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
mysql:8.0.27 \
--lower_case_table_names=1

# 启动节点2
docker run -d \
--name mgr-node2 \
--privileged=true \
--restart=always \
--network mgr-network \
-p 3322:3306 \
-v /mysql/mgr/node2/data:/var/lib/mysql \
-v /mysql/mgr/node2/conf:/etc/mysql/conf.d \
-v /mysql/mgr/node2/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
mysql:8.0.27 \
--lower_case_table_names=1

# 启动节点3
docker run -d \
--name mgr-node3 \
--privileged=true \
--restart=always \
--network mgr-network \
-p 3323:3306 \
-v /mysql/mgr/node3/data:/var/lib/mysql \
-v /mysql/mgr/node3/conf:/etc/mysql/conf.d \
-v /mysql/mgr/node3/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
mysql:8.0.27 \
--lower_case_table_names=1

8.4.4 配置组复制用户

  1. 在所有节点上创建复制用户
# 进入节点1容器
docker exec -it mgr-node1 /bin/bash
mysql -uroot -p123456

# 禁用二进制日志记录
SET SQL_LOG_BIN=0;

# 创建复制用户
CREATE USER repl@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO repl@'%';
GRANT CONNECTION_ADMIN ON *.* TO repl@'%';
GRANT BACKUP_ADMIN ON *.* TO repl@'%';
GRANT GROUP_REPLICATION_STREAM ON *.* TO repl@'%';
FLUSH PRIVILEGES;

# 启用二进制日志记录
SET SQL_LOG_BIN=1;

# 配置复制用户凭据
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='123456' FOR CHANNEL 'group_replication_recovery';

# 退出MySQL
exit;
  1. 在节点2和节点3上重复上述步骤

8.4.5 启动组复制

  1. 启动节点1(引导节点)
# 进入节点1容器
docker exec -it mgr-node1 /bin/bash
mysql -uroot -p123456

# 引导组复制
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;

# 查看组成员信息
SELECT MEMBER_HOST, MEMBER_ROLE FROM performance_schema.replication_group_members;
  1. 启动节点2和节点3
# 进入节点2容器
docker exec -it mgr-node2 /bin/bash
mysql -uroot -p123456

# 启动组复制
START GROUP_REPLICATION;

# 查看组成员信息
SELECT MEMBER_HOST, MEMBER_ROLE FROM performance_schema.replication_group_members;

在节点3上执行相同的操作。

8.4.6 验证组复制

  1. 创建测试数据
# 在任意节点上执行
CREATE DATABASE test_mgr;
USE test_mgr;
CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL);
INSERT INTO t1 VALUES (1, 'Hello Group Replication');
  1. 验证数据同步
# 在其他节点上查询
docker exec -it mgr-node2 /bin/bash
mysql -uroot -p123456 -e "SELECT * FROM test_mgr.t1;"

8.4.7 多主模式配置

  1. 停止所有节点的组复制
# 在所有节点上执行
STOP GROUP_REPLICATION;
  1. 修改配置文件
    在所有节点的配置文件中添加或修改:
# 关闭单主模式
group_replication_single_primary_mode=OFF

# 开启多主一致性检查
group_replication_enforce_update_everywhere_checks=ON
  1. 重启容器
docker restart mgr-node1 mgr-node2 mgr-node3
  1. 重新启动组复制
# 在节点1上引导组
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;

# 在节点2和节点3上启动组复制
START GROUP_REPLICATION;

8.4.8 组复制监控

  1. 查看组成员状态
SELECT * FROM performance_schema.replication_group_members;
  1. 查看组成员统计信息
SELECT * FROM performance_schema.replication_group_member_stats\G
  1. 查看连接状态
SELECT * FROM performance_schema.replication_connection_status\G
  1. 查看应用状态
SELECT * FROM performance_schema.replication_applier_status\G

9. 学习建议和重点标注

9.1 重点概念

  • 主从复制:核心概念,理解其工作原理是掌握MySQL高可用性的基础。
  • GTID:新一代复制技术,解决了传统基于位点复制的痛点。
  • 半同步复制:在数据一致性和性能之间找到平衡点。

9.2 实践要点

  • 熟练掌握Docker环境下MySQL主从复制的搭建步骤。
  • 理解并能够配置GTID复制。
  • 掌握半同步复制的配置和测试方法。

9.3 学习建议

  1. 理论结合实践:在理解概念的基础上,动手搭建主从复制环境。
  2. 关注版本差异:MySQL 8.0在复制方面有很多新特性,注意与旧版本的区别。
  3. 深入理解复制机制:理解异步、半同步、延迟复制的适用场景。
  4. 掌握故障处理:学会处理主从复制中常见的问题,如数据不一致、复制中断等。
posted @ 2025-09-06 21:32  流火无心  阅读(45)  评论(0)    收藏  举报