Mysql8.0高可用集群架构实战
-
- [📋 知识体系总览](#📋 知识体系总览)
- [一、MySQL InnoDB Cluster 概述](#一、MySQL InnoDB Cluster 概述)
-
- [✅1. 基本概述与组件](#✅1. 基本概述与组件)
- [✅2. 集群架构](#✅2. 集群架构)
- [二、搭建一主两从 InnoDB 集群](#二、搭建一主两从 InnoDB 集群)
-
- ✅1.安装3个数据库实例
- [✅2. 安装 MySQL Router 和 MySQL Shell](#✅2. 安装 MySQL Router 和 MySQL Shell)
- [✅3. InnoDB Cluster 初始化](#✅3. InnoDB Cluster 初始化)
-
- ☑️参数及权限配置预需求检测
- [☑️初始化InnoDB Cluster相关配置](#☑️初始化InnoDB Cluster相关配置)
- [✅4. 创建一主两从集群](#✅4. 创建一主两从集群)
- [三、InnoDB Cluster 运维操作](#三、InnoDB Cluster 运维操作)
-
- [✅1. 测试数据同步与主从切换](#✅1. 测试数据同步与主从切换)
- [✅2. 参数配置与节点权重](#✅2. 参数配置与节点权重)
- [✅3. 节点管理与故障恢复](#✅3. 节点管理与故障恢复)
- [✅4. 角色切换与集群销毁](#✅4. 角色切换与集群销毁)
- [四、MySQL Router 连接集群](#四、MySQL Router 连接集群)
-
- [✅1. 配置与启动Router](#✅1. 配置与启动Router)
- [✅2. 读写分离测试](#✅2. 读写分离测试)
- [五、MySQL InnoDB ReplicaSet](#五、MySQL InnoDB ReplicaSet)
-
- [✅1. 基本概述](#✅1. 基本概述)
- [✅2. 搭建一主一从复制集](#✅2. 搭建一主一从复制集)
-
- ☑️环境准备
- ☑️配置复制集
- ☑️测试数据同步
- [☑️配置 MySQL Router](#☑️配置 MySQL Router)
- ☑️测试Router
- [📋 全文总结](#📋 全文总结)
-
- [✅1. 架构演进路线](#✅1. 架构演进路线)
- [✅2. InnoDB Cluster 核心组件对比](#✅2. InnoDB Cluster 核心组件对比)
- [✅3. InnoDB Cluster vs ReplicaSet](#✅3. InnoDB Cluster vs ReplicaSet)
- [✅4. 关键命令速查表](#✅4. 关键命令速查表)
- [✅5. 面试核心要点](#✅5. 面试核心要点)

📋 知识体系总览
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需要满足的要求如下:
-
必须开启二进制日志,日志格式为ROW:
--log-bin和binlog_format=row(默认) -
必须开启副本更新日志:
log_replica_updates=ON(默认) -
必须开启GTID:
gtid_mode=ON和enforce_gtid_consistency=ON -
存储引擎只能使用InnoDB 。最好禁用其他引擎:
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY" -
从8.0.23开始,集群中的实例要启用并行复制 :
inibinlog_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. 面试核心要点
- InnoDB Cluster 的三个组件:MGR(数据同步)+ MySQL Shell(管理)+ MySQL Router(路由)
- Router 端口:6446(读写/经典)、6447(只读/经典)、6448(读写/X协议)、6449(只读/X协议)
- 集群节点状态:ONLINE / OFFLINE / RECOVERING / ERROR / UNREACHABLE / MISSING
- 故障转移:InnoDB Cluster自动完成,InnoDB ReplicaSet需要手动触发
- 关键端口:3306(MySQL服务)、33061(MGR内部通信)
- 权重机制:memberWeight(0-100),影响主节点选举