10.Mysql8.0高可用集群架构实战

Mysql8.0高可用集群架构实战

📋 知识体系总览

复制代码
Mysql8.0高可用集群架构实战
├── 一、MySQL InnoDB Cluster 概述
│   ├── ✅1. 基本概述与组件
│   └── ✅2. 集群架构
├── 二、搭建一主两从 InnoDB 集群
│   ├── ✅1. 安装3个数据库实例
│   ├── ✅2. 安装 MySQL Router 和 MySQL Shell
│   ├── ✅3. InnoDB Cluster 初始化
│   └── ✅4. 创建一主两从集群
├── 三、InnoDB Cluster 运维操作
│   ├── ✅1. 测试数据同步与主从切换
│   ├── ✅2. 参数配置与节点权重
│   ├── ✅3. 节点管理与故障恢复
│   └── ✅4. 角色切换与集群销毁
├── 四、MySQL Router 连接集群
│   ├── ✅1. 配置与启动Router
│   └── ✅2. 读写分离测试
├── 五、MySQL InnoDB ReplicaSet
│   ├── ✅1. 基本概述
│   ├── ✅2. 搭建一主一从复制集
└── 📋 全文总结

一、MySQL InnoDB Cluster 概述

✅1. 基本概述与组件

官方文档:https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-innodb-cluster.html

InnoDB Cluster是MySQL官方实现高可用+读写分离的架构方案,包含以下组件:

组件 说明
MySQL Group Replication (MGR) MySQL的主从同步高可用方案,包括数据同步及角色选举
MySQL Shell InnoDB Cluster的管理工具,用来创建和管理集群
MySQL Router 业务流量入口,支持对MGR的主从角色判断,可以配置不同的端口分别对外提供读写服务,实现读写分离

📝 核心: MySQL Router与组复制和MySQL Shell高度整合,只有将其与组复制和MySQL Shell共同使用,才能够称为InnoDB Cluster。

✅2. 集群架构

InnoDB Cluster将三个MySQL数据库实例构成一个高可用集群。其中一个实例是具有读/写 能力的主要成员(Primary),其他两个实例是具有只读能力的次要成员(Secondary)。组复制将数据从主要成员复制到次要成员。MySQL Router将客户端应用程序连接到集群的主要成员。

二、搭建一主两从 InnoDB 集群

✅1.安装3个数据库实例

架构规划:

主机名(角色) server_id 宿主机IP 容器固定IP DB Port
mgr-node1 (Primary) 1 192.168.65.223 172.28.0.10 3321→3306
mgr-node2 (Secondary) 2 192.168.65.223 172.28.0.11 3322→3306
mgr-node3 (Secondary) 3 192.168.65.223 172.28.0.12 3323→3306
☑️环境准备
bash 复制代码
# 创建组复制的网络(指定子网和网关,便于固定IP)
docker network create --driver bridge --subnet 172.28.0.0/24 --gateway 172.28.0.1 mgr-network

# 创建数据目录
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

列出所有Docker网络及其子网:

复制代码
docker network inspect $(docker network ls -q) | grep -E "Name|Subnet"
☑️创建配置文件

创建/mysql/mgr/node1/conf/custom.cnf,mgr-node2和mgr-node3的配置文件只需修改 server_id 分别为2和3。添加以下配置:

bash 复制代码
vim /mysql/mgr/node1/conf/custom.cnf
vim /mysql/mgr/node2/conf/custom.cnf
vim /mysql/mgr/node3/conf/custom.cnf
ini 复制代码
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8

[mysqld]
# 指定server_id,三个实例需要分别改为1/2/3
server_id=1

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

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

# 启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64

# 对于Group Replication,数据必须存储在InnoDB事务存储引擎中
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
ini 复制代码
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8

[mysqld]
# 指定server_id,三个实例需要分别改为1/2/3
server_id=2

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

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

# 启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64

# 对于Group Replication,数据必须存储在InnoDB事务存储引擎中
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
ini 复制代码
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8

[mysqld]
# 指定server_id,三个实例需要分别改为1/2/3
server_id=3

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

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

# 启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64

# 对于Group Replication,数据必须存储在InnoDB事务存储引擎中
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
☑️运行MySQL容器

为了便于测试,启动容器时指定好IP、hostname。

mgr-node1:ip :172.28.0.10、端口:3321

bash 复制代码
docker run -d \
  --name mgr-node1 \
  --privileged=true \
  --restart=always \
  --ip 172.28.0.10 \
  --hostname mgr-node1 \
  --add-host mgr-node2:172.28.0.11 \
  --add-host mgr-node3:172.28.0.12 \
  --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

mgr-node2 :ip :72.28.0.11、端口:3322

bash 复制代码
docker run -d \
  --name mgr-node2 \
  --privileged=true \
  --restart=always \
  --ip 172.28.0.11 \
  --hostname mgr-node2 \
  --add-host mgr-node1:172.28.0.10 \
  --add-host mgr-node3:172.28.0.12 \
  --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

mgr-node3 :ip :72.28.0.12、端口:3323

bash 复制代码
docker run -d \
  --name mgr-node3 \
  --privileged=true \
  --restart=always \
  --ip 172.28.0.12 \
  --hostname mgr-node3 \
  --add-host mgr-node1:172.28.0.10 \
  --add-host mgr-node2:172.28.0.11 \
  --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

可以通过下面命令查询同期的配置参数,比如IP,网关等信息:

复制代码
docker inspect mgr-node1
docker inspect mgr-node2
docker inspect mgr-node3
☑️配置宿主机hosts映射
bash 复制代码
vim /etc/hosts
# 添加:
172.28.0.10  mgr-node1
172.28.0.11  mgr-node2
172.28.0.12  mgr-node3
☑️配置远程访问
sql 复制代码
-- 所有实例都执行
# 以node1为例
docker exec -it mgr-node1 /bin/bash
mysql -u root -p123456
#进入mysql执行
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
flush privileges;

✅2. 安装 MySQL Router 和 MySQL Shell

MySQL Router: MySQL Proxy的后继产品,提供MySQL协议的路由器功能,用来实现读写分离、负载均衡和高可用性。

下载地址:https://downloads.mysql.com/archives/router/

bash 复制代码
# CentOS 7 安装 MySQL Router
wget https://downloads.mysql.com/archives/get/p/41/file/mysql-router-community-8.0.27-1.el7.x86_64.rpm
rpm -ivh mysql-router-community-8.0.27-1.el7.x86_64.rpm
bash 复制代码
# Ubuntu 20.04 安装 MySQL Router
wget https://downloads.mysql.com/archives/get/p/41/file/mysql-router-community_8.0.27-1ubuntu20.04_amd64.deb
sudo dpkg -i mysql-router-community_8.0.27-1ubuntu20.04_amd64.deb

# 3. 如果提示依赖缺失,执行以下命令自动补齐依赖
sudo apt-get install -f

# 4. 验证安装
mysqlrouter --version

MySQL Shell: InnoDB Cluster的管理工具。

下载地址:https://downloads.mysql.com/archives/shell/

bash 复制代码
# CentOS 7 安装 MySQL Shell
wget https://downloads.mysql.com/archives/get/p/43/file/mysql-shell-8.0.27-1.el7.x86_64.rpm
rpm -ivh mysql-shell-8.0.27-1.el7.x86_64.rpm
bash 复制代码
# Ubuntu20.04 安装 MySQL Shell
# 1. 下载 mysql-shell 的 deb 包(Ubuntu 20.04 / 8.0.27 版本)
wget https://downloads.mysql.com/archives/get/p/43/file/mysql-shell_8.0.27-1ubuntu20.04_amd64.deb

# 2. 安装 deb 包(对应 CentOS 的 rpm -ivh)
sudo dpkg -i mysql-shell_8.0.27-1ubuntu20.04_amd64.deb

# 3. 若提示依赖缺失,执行以下命令自动补齐
sudo apt-get install -f

# 4. 验证安装
mysqlsh --version

MySQL Shell 教程: https://share.note.youdao.com/s/IpZEoHG0

MySQL Shell的操作依赖两个核心端口,防火墙必须开放这些端口才能保证集群正常通信:

端口 用途 说明
3306 MySQL服务端口 MySQL Shell连接MySQL服务器的默认端口
33061 Group Replication通信端口 集群节点之间同步数据/状态的默认端口

当防火墙阻塞上述端口时,会出现:

  • 3306被阻塞:ERROR: MySQL server at 'mgr-node2:3306' can't connect to 'mgr-node1:3306'
  • 33061被阻塞:ERROR: RuntimeError: Server address configuration error

✅3. InnoDB Cluster 初始化

☑️参数及权限配置预需求检测
javascript 复制代码
// 进入MySQL Shell
mysqlsh root@192.168.80.3:3321 --js
mysqlsh root@mgr-node1:3306 --js

// 检查实例是否符合InnoDB Cluster的参数及权限配置要求
dba.checkInstanceConfiguration('root@mgr-node1:3306')
dba.checkInstanceConfiguration('root@mgr-node2:3306')
dba.checkInstanceConfiguration('root@mgr-node3:3306')

如果验证通过返回ok。

如果验证没通过,比如出现下面的日志提示,需要mysql实例开启gtid和指定server_id

*搭建InnoDB Cluster需要满足的要求如下:

  1. 必须开启二进制日志,日志格式为ROW:--log-binbinlog_format=row(默认)

  2. 必须开启副本更新日志:log_replica_updates=ON(默认)

  3. 必须开启GTID:gtid_mode=ONenforce_gtid_consistency=ON

  4. 存储引擎只能使用InnoDB 。最好禁用其他引擎:disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"

  5. 从8.0.23开始,集群中的实例要启用并行复制

    ini 复制代码
    binlog_transaction_dependency_tracking=WRITESET
    slave_preserve_commit_order=ON
    slave_parallel_type=LOGICAL_CLOCK
    transaction_write_set_extraction=XXHASH64
☑️初始化InnoDB Cluster相关配置
javascript 复制代码
// 对每个实例配置InnoDB Cluster相关参数
dba.configureInstance('root@mgr-node1:3306')
dba.configureInstance('root@mgr-node2:3306')
dba.configureInstance('root@mgr-node3:3306')

✅4. 创建一主两从集群

☑️集群常用命令速查
bash 复制代码
#会列出dba相关指令
dba.help();
#列出详细指令的用法
dba.help('deploySandboxInstance');
#检查节点配置实例,用于加入cluster之前
dba.checkInstanceConfiguration("root@hostname:3306");  
#节点初始化
dba.configureInstance('root@hostname:3306'); 
#重启集群
dba.rebootClusterFromCompleteOutage('myCluster');  
#会列出集群相关指令
cluster.help();       
#创建集群
var cluster = dba.createCluster('myCluster');                              
#获取当前集群实例
var cluster = dba.getCluster('myCluster');   
查看集群状态
cluster.status();             
#检查cluster节点状态 
cluster.checkInstanceState("root@hostname:3306") ;                             
#增加节点 
cluster.addInstance("root@hostname:3306") ;               
#删除节点 
cluster.removeInstance("root@hostname:3306") ;            
#强制删除节点
cluster.removeInstance('root@hostname:3306',{force:true});    
#  状态为missing的节点可以重新加入集群 
cluster.rejoinInstance("root@hostname:3306")
#解散集群 
cluster.dissolve({force:true}) ;                          
#集群描述 
cluster.describe();                                      
☑️创建集群
javascript 复制代码
// 进入主节点创建集群
mysqlsh root@192.168.80.3:3321 --js 或 mysqlsh root@mgr-node1:3306 --js

// 创建一个cluster,命名为 'myCluster'
var cluster = dba.createCluster('myCluster');

// 创建成功后,查看cluster状态
cluster.status();
☑️添加副本实例
javascript 复制代码
// 初始化第二个和第三个实例
cluster.addInstance('root@mgr-node2:3306');
cluster.addInstance('root@mgr-node3:3306');

// 查看cluster状态
cluster.status();

第一次创建副本示例,需要选择c进行克隆主机

☑️完整搭建步骤总结
javascript 复制代码
// === mgr-node1 ===
# 进入主节点
mysqlsh root@mgr-node1:3306 --js
# 参数权限检查
dba.checkInstanceConfiguration('root@mgr-node1:3306');
# 初始化
dba.configureInstance('root@mgr-node1:3306');
# 创建集群
var cluster = dba.createCluster('myCluster');
# 查看cluster状态
cluster.status();

// === mgr-node2 ===
# 参数权限检查
dba.checkInstanceConfiguration('root@mgr-node2:3306');
# 初始化
dba.configureInstance('root@mgr-node2:3306');
# 添加副本
cluster.addInstance('root@mgr-node2:3306');

// === mgr-node3 ===
# 参数权限检查
dba.checkInstanceConfiguration('root@mgr-node3:3306');
# 初始化
dba.configureInstance('root@mgr-node3:3306');
# 添加副本
cluster.addInstance('root@mgr-node3:3306');

// 查看最终集群状态
cluster.status();

集群节点状态说明:

注意:搭建成功后,集群状态显示:"status": "OK""statusText": "Cluster is ONLINE and can tolerate up to ONE failure."

状态 说明
ONLINE 节点状态正常
OFFLINE 实例在运行,但没有加入任何Cluster
RECOVERING 实例已加入Cluster,正在同步数据
ERROR 同步数据发生异常
UNREACHABLE 与其他节点通讯中断(网络问题或节点crash)
MISSING 节点已加入集群,但未启动group replication

三、InnoDB Cluster 运维操作

✅1. 测试数据同步与主从切换

☑️测试数据同步
sql 复制代码
#主节点 mgr-node1
[root@192-168-65-223 ~]# docker exec -it mgr-node1 bash
root@mgr-node1:/# mysql -uroot -p123456
mysql>
create database test;
use test;
create table t(x int primary key auto_increment,y int);
insert into t(x,y) value(1,1);

📝 注意: 如果创建表没有设置主键,会抛出错误:ERROR 3098 (HY000): The table does not comply with the requirements by an external plugin.

sql 复制代码
-- 查看其他节点,数据是否同步
-- mgr-node2
use test;
select * from t;  -- 确认数据已同步
☑️测试主从切换
bash 复制代码
# 停掉主节点
docker stop mgr-node1
javascript 复制代码
#停掉主节点
[root@192-168-65-223 ~]# docker stop mgr-node1

# 连接到mgr-node2
MySQL  mgr-node1:3306 ssl  JS > \connect root@mgr-node2:3306
# 获取集群实例
 MySQL  mgr-node2:3306 ssl  JS > var cluster=dba.getCluster();
# 查看集群状态
MySQL  mgr-node2:3306 ssl  JS > cluster.status()

可以看到mgr-node2升级为主节点

输出关键信息:

  • mgr-node2:3306"memberRole": "PRIMARY", "mode": "R/W"
  • mgr-node1:3306"status": "(MISSING)"

将主机重启恢复

bash 复制代码
# 启动mgr-node1节点,它会自动恢复并重新加入集群
docker start mgr-node1
javascript 复制代码
// 再次查看状态,mgr-node1恢复为ONLINE
cluster.status();
// "statusText": "Cluster is ONLINE and can tolerate up to ONE failure."

查看集群状态,发现mgr-node1正在恢复,最终正常

✅2. 参数配置与节点权重

参数配置分为两种方式:

  • cluster.setOption() --- 设置所有节点的参数
  • cluster.setInstanceOption() --- 对指定节点配置属性
javascript 复制代码
// 将所有节点的权重都改为50
var cluster = dba.getCluster()
cluster.setOption("memberWeight", 50)

// 重新加入集群重试次数改为5次
cluster.setOption("autoRejoinTries", 5)

// 将指定节点的权重改为75
cluster.setInstanceOption("mgr-node2:3306", "memberWeight", 75)

配置节点权重(memberWeight):

memberWeight 值域为0到100之间的整数,缺省值为50。该值是故障转移时自动选举主节点的百分比权重,具有较高 memberWeight 值的实例更有可能在单主集群中被选为主节点。

javascript 复制代码
// 查看集群的参数配置
cluster.options()

// 在集群创建时配置权重
dba.createCluster('myCluster', {memberWeight: 75})
cluster.addInstance('mgr-node2:3306', {memberWeight: 50})
cluster.addInstance('mgr-node3:3306', {memberWeight: 25})

// 在集群创建完成后修改权重
var cluster = dba.getCluster()
cluster.setInstanceOption('mgr-node1:3306', 'memberWeight', 100)
cluster.setInstanceOption('mgr-node2:3306', 'memberWeight', 50)
cluster.setInstanceOption('mgr-node3:3306', 'memberWeight', 25)

✅3. 节点管理与故障恢复

☑️将节点重新加入集群

状态为MISSING的节点,通常是组复制关闭或中断状态,可以用 cluster.rejoinInstance() 重新加入集群:

javascript 复制代码
cluster.rejoinInstance('root@hostname:3306')

如果一些参数做了修改(如server_uuid变更),导致rejoin失败,则需要将节点从集群中删除后重新加入:

javascript 复制代码
cluster.removeInstance("root@hostname:3306", {force: true})
cluster.rescan()
cluster.addInstance("root@hostname:3306")
☑️集群多数节点异常恢复

当集群多个节点异常,则失去了仲裁机制,剩下的一个节点:

javascript 复制代码
// 将集群剥离为单节点运行
cluster.forceQuorumUsingPartitionOf("root@hostname:3306")

// 重新加另外2个节点加入
cluster.rejoinInstance("root@hostname2:3306")
cluster.rejoinInstance("root@hostname3:3306")

✅4. 角色切换与集群销毁

☑️单主模式-指定主节点切换
javascript 复制代码
var cluster = dba.getCluster()
cluster.setPrimaryInstance('homename:3306')
cluster.status()
☑️单主模式和多主模式相互切换
javascript 复制代码
// 切换为多主模式
var cluster = dba.getCluster()
cluster.switchToMultiPrimaryMode()

// 指定明确的主节点将多主模式切换为单主模式
 

将单主模式切换为多主模式的效果

☑️创建集群管理用户
javascript 复制代码
cluster.setupAdminAccount('fox')

// 经典MySQL协议连接
mysqlsh --mysql -hmgr-node1 -ufox
// X协议连接
mysqlsh --mysqlx -hmgr-node1 -ufox
☑️销毁集群

删除与群集关联的所有元数据和配置,并禁用实例上的组复制,但不会删除在实例之间复制的任何数据。要再次创建集群,使用dba.createCluster()

javascript 复制代码
var cluster = dba.getCluster()
cluster.dissolve()

四、MySQL Router 连接集群

✅1. 配置与启动Router

bash 复制代码
# 配置路由器(引导启动、一次性)
mysqlrouter --bootstrap root@mgr-node2:3306 --force --user=root

# 或者指定host
mysqlrouter --bootstrap root@mgr-node2:3306 --force --user=root --report-host mgr

注意:如果用户之前为该实例配置过路由,可以通过指定 --force 选项强制引导启动。

Router端口说明:

协议 读写端口 只读端口
MySQL经典协议 6446 6447
X协议 6448 6449
bash 复制代码
# 启动路由器
mysqlrouter &

路由器已经成功启动。现在,使用MySQL Shell连接路由器进行验证。

复制代码
#连接mysqlrouter
[root@192-168-65-223 ~]# mysqlsh root@localhost:6446 --sql
MySQL  localhost:6446 ssl  SQL > use test;
MySQL  localhost:6446 ssl  test  SQL > select * from t;

查看集群成员信息

复制代码
MySQL  localhost:6446 ssl  test  SQL > select * from performance_schema.replication_group_members;

✅2. 读写分离测试

bash 复制代码
# 连接Router
mysqlsh root@localhost:6446 --sql
sql 复制代码
-- 通过Router查询数据
use test;
select * from t;

-- 查看集群成员信息
select * from performance_schema.replication_group_members;

读写分离验证:

端口 类型 验证结果
6446 读写端口 可以读写(插入/查询)
6447 只读端口 只能读取,插入数据报错

📝 核心: MySQL Router自动将写请求路由到Primary节点(6446端口),读请求路由到Secondary节点(6447端口),实现透明的读写分离。

五、MySQL InnoDB ReplicaSet

✅1. 基本概述

MySQL Innodb Cluster = MySQL Shell + MySQL Router + MySQL Group Replication(MGR),全程由 MySQL Shell 来管理操作 MGR 的聚合套件。MySQL 8.0.19 发布后,这种组合延伸到 MySQL Replication(主从复制),也就是 MySQL Shell + MySQL Router + MySQL Replication。

InnoDB ReplicaSet至少由两个MySQL服务器实例组成,并提供用户熟知的主从复制功能,例如读取横向扩展和数据安全性。InnoDB ReplicaSet使用以下MySQL技术。

  • MySQL Shell:MySQL的高级客户端、管理工具,可以用来管理复制集。
  • MySQL复制:一组MySQL实例,通过复制能够提供可用性和异步读取的横向扩展。
  • MySQL Router:一种轻量级的中间件,可在应用程序和InnoDB ReplicaSet之间提供透明的路由。InnoDB ReplicaSet的接口类似于InnoDB Cluster,用户可以利用MySQL Shell使用MySQL实例和MySQL Router。

与InnoDB集群相比,InnoDB ReplicaSet具有多个限制,因此,官方建议尽可能部署InnoDB群集。通常,InnoDB ReplicaSet本身不能提供高可用性。InnoDB ReplicaSet的限制包括:

  • 没有自动故障转移。如果主服务器不可用,则需要使用AdminAPI手动触发故障转移,然后才能再次进行任何更改。但是,辅助实例仍然可用于读取。
  • **无法防止因意外停止或不可用而导致部分数据丢失。**暂停之前尚未应用的事务可能会丢失。
  • **无法防止崩溃或不可用后出现不一致情况。**如果故障转移在辅助节点仍可用的情况下提升了辅助节点(例如,由于网络分区),则可能会因脑裂而引起不一致

InnoDB ReplicaSet vs InnoDB Cluster:

维度 InnoDB ReplicaSet InnoDB Cluster
自动故障转移 ❌ 不支持,需手动触发 ✅ 支持
数据丢失防护 ❌ 可能丢失未应用的事务 ✅ 通过Paxos协议保证
脑裂防护 ❌ 无法防止不一致 ✅ 通过仲裁机制防止
适用场景 异步复制+读写分离 高可用+强一致性

📝 官方建议: 尽可能部署InnoDB Cluster。InnoDB ReplicaSet本身不能提供高可用性。

✅2. 搭建一主一从复制集

架构规划:

主机名(角色) server_id 宿主机IP 容器固定IP DB Port
rs-node1 (Primary) 21 192.168.65.223 172.29.0.20 3331→3306
rs-node2 (Secondary) 22 192.168.65.223 172.29.0.21 3332→3306
☑️环境准备
bash 复制代码
# 创建组复制的网络  保证三个mysql容器之间可以通过容器名访问
docker network create --driver bridge --subnet 172.29.0.0/24 --gateway 172.290.1 rs-network

mkdir -p /mysql/rs/node1/data /mysql/rs/node1/conf /mysql/rs/node1/log
mkdir -p /mysql/rs/node2/data /mysql/rs/node2/conf /mysql/rs/node2/log


#以rs-node1配置为例,创建/mysql/rs/node1/conf/custom.cnf,添加以下配置:
vim /mysql/rs/node1/conf/custom.cnf
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8
[mysqld]
#指定sever_id,多个Mysql实例需要分别改为对应的sever_id
server_id=21
# 必须开启GTID支持
gtid_mode=ON
enforce_gtid_consistency=ON
# 启用二进制日志
log-bin=mysql-bin
#启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64

# rs-node2同上,注意配置文件路径和修改server_id
vim /mysql/rs/node2/conf/custom.cnf
[mysql]
# 设置mysql客户端默认编码
default-character-set=utf8
[mysqld]
#指定sever_id,多个Mysql实例需要分别改为对应的sever_id
server_id=22
# 必须开启GTID支持
gtid_mode=ON
enforce_gtid_consistency=ON
# 启用二进制日志
log-bin=mysql-bin
#启用并行复制
binlog_transaction_dependency_tracking=WRITESET
replica_preserve_commit_order=ON
replica_parallel_type=LOGICAL_CLOCK
transaction_write_set_extraction=XXHASH64


#运行mysql容器
# 为了便于测试,启动容器时指定好IP、hostname
docker run  -d  \
--name rs-node1 \
--privileged=true \
--restart=always \
--ip 172.29.0.20 \
--hostname rs-node1 \
--add-host  rs-node2:172.29.0.21 \
--network  rs-network \
-p 3331:3306 \
-v /mysql/rs/node1/data:/var/lib/mysql \
-v /mysql/rs/node1/conf:/etc/mysql/conf.d  \
-v /mysql/rs/node1/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai mysql:8.0.27 \
--lower_case_table_names=1


docker run  -d  \
--name rs-node2 \
--privileged=true \
--restart=always \
--ip 172.29.0.21 \
--hostname rs-node2 \
--add-host  rs-node1:172.29.0.20 \
--network  rs-network \
-p 3332:3306 \
-v /mysql/rs/node2/data:/var/lib/mysql \
-v /mysql/rs/node2/conf:/etc/mysql/conf.d  \
-v /mysql/rs/node2/log:/logs \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai mysql:8.0.27 \
--lower_case_table_names=1



# 在宿主机上配置mysql容器的ip和host映射
vim /etc/hosts
172.29.0.20  rs-node1
172.29.0.21  rs-node2

所有实例分别配置远程访问

复制代码
# 以node1为例
docker exec -it rs-node1 /bin/bash
mysql -u root -p123456
#进入mysql执行
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
flush privileges;
☑️配置复制集

1)初始化主节点,创建复制集

复制代码
#进入主节点
mysqlsh root@rs-node1:3306 --js
# 初始化
dba.configureReplicaSetInstance('root@rs-node1:3306')
# 创建复制集,使用异步复制
var rs = dba.createReplicaSet("myrs")
#查看状态
rs.status()

2)添加副本节点

复制代码
#将实例添加到复制集
rs.addInstance('root@rs-node2:3306')
☑️测试数据同步
sql 复制代码
#主节点 rs-node1
[root@192-168-65-223 ~]# docker exec -it rs-node1 bash
root@mgr-node1:/# mysql -uroot -p123456
mysql>
create datebase test;
use test;
create table t(x int primary key auto_increment,y int);
insert into t(x,y) value(1,1);
select * from t;

# 进入从节点rs-node2,查看数据是否同步过来
[root@192-168-65-223 ~]# docker exec -it rs-node2 bash
root@rs-node2:/# mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1596
Server version: 8.0.27 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from t;
+---+------+
| x | y    |
+---+------+
| 1 |    1 |
+---+------+
1 row in set (0.00 sec)
☑️配置 MySQL Router
bash 复制代码
# 配置路由器
[root@192-168-65-223 ~]# mysqlrouter --bootstrap root@rs-node1:3306 --force --user=root

重启Mysql Router

复制代码
[root@192-168-65-223 ~]# ps -ef|grep mysqlrouter
root     16993 14238  6 11:30 pts/1    00:18:01 mysqlrouter
root     21637 14178  0 16:22 pts/0    00:00:00 grep --color=auto mysqlrouter
[root@192-168-65-223 ~]# kill -9 16993
# 启动Mysql Router
[root@192-168-65-223 ~]# mysqlrouter &
☑️测试Router

用户可以通过连接本机的6446端口连接到MySQL实例

bash 复制代码
[root@192-168-65-223 ~]# mysqlsh root@localhost:6446 --sql
# 可以查询到插入的测试数据
 MySQL  localhost:6446 ssl  SQL > select * from test.t;
+---+---+
| x | y |
+---+---+
| 1 | 1 |
+---+---+

📋 全文总结

✅1. 架构演进路线

复制代码
MySQL Replication → 组复制(MGR) → InnoDB Cluster → InnoDB ReplicaSet
                    (手动管理)      (Shell+Router+MGR)   (Shell+Router+Replication)

✅2. InnoDB Cluster 核心组件对比

组件 职责 关键点
MySQL Group Replication 数据同步+角色选举 Paxos协议,单主/多主模式
MySQL Shell 集群管理工具 dba.xxx() JavaScript API
MySQL Router 流量入口+读写分离 6446(读写)/6447(只读)

✅3. InnoDB Cluster vs ReplicaSet

特性 InnoDB Cluster InnoDB ReplicaSet
基础技术 Group Replication 异步复制
自动故障转移 ❌(需手动)
数据一致性 强一致(Paxos) 最终一致(异步)
节点数 3+(推荐) 2+
适用场景 高可用核心业务 读写分离+备份

✅4. 关键命令速查表

javascript 复制代码
// === 集群管理 ===
dba.checkInstanceConfiguration('root@host:3306')    // 检查配置
dba.configureInstance('root@host:3306')              // 初始化实例
dba.createCluster('myCluster')                       // 创建集群
dba.getCluster('myCluster')                          // 获取集群
dba.rebootClusterFromCompleteOutage('myCluster')     // 重启集群

// === 节点管理 ===
cluster.addInstance('root@host:3306')                // 添加节点
cluster.removeInstance('root@host:3306')             // 删除节点
cluster.rejoinInstance('root@host:3306')             // 重新加入
cluster.status()                                     // 查看状态

// === 角色切换 ===
cluster.setPrimaryInstance('host:3306')              // 指定主节点
cluster.switchToMultiPrimaryMode()                   // 切换多主
cluster.switchToSinglePrimaryMode('host:3306')       // 切换单主

// === 配置管理 ===
cluster.setOption("memberWeight", 50)                // 全局权重
cluster.setInstanceOption('host:3306', 'memberWeight', 75)  // 指定节点权重
cluster.setupAdminAccount('user')                    // 创建管理用户
cluster.dissolve()                                   // 销毁集群

// === 复制集 ===
dba.configureReplicaSetInstance('root@host:3306')    // 初始化复制集实例
dba.createReplicaSet("myrs")                         // 创建复制集
rs.addInstance('root@host:3306')                     // 添加副本
rs.status()                                          // 查看状态

// === Router ===
mysqlrouter --bootstrap root@host:3306 --force --user=root  // 配置Router
mysqlrouter &                                          // 启动Router
cluster.listRouters()                                  // 查看已注册Router

✅5. 面试核心要点

  1. InnoDB Cluster 的三个组件:MGR(数据同步)+ MySQL Shell(管理)+ MySQL Router(路由)
  2. Router 端口:6446(读写/经典)、6447(只读/经典)、6448(读写/X协议)、6449(只读/X协议)
  3. 集群节点状态:ONLINE / OFFLINE / RECOVERING / ERROR / UNREACHABLE / MISSING
  4. 故障转移:InnoDB Cluster自动完成,InnoDB ReplicaSet需要手动触发
  5. 关键端口:3306(MySQL服务)、33061(MGR内部通信)
  6. 权重机制:memberWeight(0-100),影响主节点选举