MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

时间:2023-02-15 13:05:33

高可用集群的基本特点

负载均衡 / 读写分离 / 故障转移
本文以此为目标,利用 mysql-shell、mysql-router,基于 docker 的环境架构(篇幅太长,内容多了点儿)。

名词 解释
GR Group Replication;集群间的主从节点数据复制,利用 gtid、binlog 等确保所有节点数据的一致。
DDL Data Definition Language;操作库本身的语句。如 CREATE/ALTER/DROP等语句;自动提交当前事务;不能回滚。
DML Data Manipulation Language;针对数据的操作,如 CRUD,可回滚。

本文主要阐述内容:

    • 集群化配置项的作用说明
    • mysql-shell 组建管理集群
    • mysql-router 集群路由
    • 集群总体测试验证

二、环境说明

2.1 环境详细

名称 标签 角色
Rockylinux 9.1 本次整体测试虚拟机;可参考:https://rockylinux.org
mysql-shell 8.0.31 用来管理集群
mysql-router 8.0.31 集群路由服务
docker 20.10.22 集群服务容器载体
docker image:oraclelinux 9-slim 用来部署 mysql-router 的镜像
docker image:mysql 8.0.31 集群实例服务镜像
mysql-cli 8.0.31 用来测试验证连接的客户端

2.2 环境架构

    • Linux VM 中安装 mysql-shell
    • Linux VM 中安装 docker(运行3个mysql容器、一个mysql-router容器)
    • Linux VM 中安装 mysql-client

环境架构图示例

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

应用安装层次图

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

三、环境准备

- docker 的安装在这里省略。
- 网络地址全部使用 hostname 代替 IP 相互通信。
- 所有 MySQL 系相关的应用版本计划统一为 8.0.31。
- 所有 MySQL 涉及到的账号,为了测试便捷,以下都用 root / 统一密码操作。

3.1 docker 拉取所需的镜像

mysql image:利用官方提供的镜像,后续运行容器作为集群的节点

oraclelinux image:官方提供的系统镜像,后续为运行 mysql-router 的容器

# 拉取oraclelinux系统镜像
docker pull oraclelinux:9-slim
# 拉取MySQL官网提供的镜像
docker pull mysql:8.0.31

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

3.2 docker 创建集群专用网段

集群,当然建议固定 ip,甚至配置集群 hosts;这对于集群内部网络高并发下是很有必要的网络优化。

为此,这里单独创建一个虚拟网络,后续应用到集群中。(计划本次测试不涉及跨主机的网络转发)

# 这里创建一个名称为 br-mysql-clus 的自定义网络,计划集群所有节点处在同一网段下
docker network create --subnet=12.12.0.0/24 --gateway=12.12.0.254 br-mysql-clus

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

3.3 集群 hosts 设置

计划集群中的每个节点都用固定 IP,并指明 hostname,以 hostname 相互通信(这在集群中提升了通信的效率)

计划所有的容器 hosts 文件都绑定到 Linux VM/etc/hosts;所以主机 hosts 设置所有节点的 IP > hostname:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

# 追加集群各节点的 IP > hostname
# 以下定义,为后续容器的运行做准备
12.12.0.1       mc1    # mysql cluster node 1
12.12.0.2       mc2    # mysql cluster node 2
12.12.0.3       mc3    # mysql cluster node 3
12.12.0.5       mr     # mysql router

四、基于集群的 MySQL8 配置项说明

4.1 必须配置项

如果不配置以下各项,后续组建集群的 shell 会逐一列出不符合集群要求的项,并提醒完成必须的配置。

server_id:集群各节点唯一标识,必须为数字型;基于此配置会自动生成配置项 server_uuid 的值。

gtid_mode / dnforce_gtid_consistency:开启组复制 / 并保持事务的一致性,这个很重要。

group_replication_single_primary_mode:本次计划的 单主多从 集群模式。

binlog_transaction_dependency_tracking:集群同步数据时更精确的事务处理方式。

group_replication_group_name:统一的名称才可识别为属于同一个集群。

[mysqld]
# 各节点的唯一识别,各节点cnf唯一不同之处,只能是数字
server_id = 1
# 开启组复制的集群数据同步功能
gtid_mode = ON
enforce_gtid_consistency = ON
# 指明单主多从模式
loose-group_replication_single_primary_mode = ON
loose-binlog_transaction_dependency_tracking = WRITESET
# 集群名称,必为有效的UUID
loose-group_replication_group_name = "a53e2dec-a5fe-11ed-99b8-080027c5c3a3"

什么是 GTID

全局事务标识符;GTID 是创建的唯一标识符,基于事务的数据复制,可以识别和跟踪源服务器上提交的每个事务,在源和拓扑服务器上均唯一;它在源服务器上提交并由任何副本应用,源和副本之间始终保留GTID,只要在源上提交的所有事务也在副本上提交,在源上提交的事务只能在副本上应用一次,就可以保证两者之间的一致性。

4.2 需要关注的配置项

配置项说明解释:

group_replication_start_on_boot:节点加入集群时,自动开始复制 Master 数据功能,以保持节点间数据一致。

group_replication_bootstrap_group:集群启动后是否作为 Master 节点,自动开始RG;建议都设为 OFF。

group_replication_local_address:集群内各节点之间,当前节点对外的通讯地址。

group_replication_group_seeds:集群启动时,组建的基本节点。

[mysqld]
# 启动后自动运行组复制,默认=ON
#loose-group_replication_start_on_boot = ON

# 重启后的集群以哪个实例的数据为准的复制同步过程
#loose-group_replication_bootstrap_group = OFF

# 明确本节点的对外通信地址(不是必须,shell脚本可覆盖代替)
# 当 communication_stack = MYSQL 时,以下端口只能3306
# 当 communication_stack = XCOM 时,以下端口建议33061
#loose-group_replication_local_address="{host}:3306"

# 种子节点,由每个节点的通信地址组成(不是必须,shell脚本可覆盖代替)
#loose-group_replication_group_seeds="{host}:3306,{host}:3306,{host}:3306"

需要注意的配置项 group_replication_bootstrap_group

假设1:所有节点都设为 OFF,重启的集群不会自动开始组复制(GR)功能
假设2:多节点设为 ON,系统分不清以哪个节点为基准的组复制(GR)功能(脑裂现象)
假设3:固定一个节点设为 ON,此节点的数据在集群中不一定是最完整的

所以,重启后的集群,人为的选择 Master,手动启动组复制(GR)最为妥当

方案1:集群启动前,选好一台 ON 作为 Master,集群启动后,需改为 OFF
方案2:在被人为认定的 Master 主机上,手动启动GR,如下脚本:
  mysql> SET GLOBAL group_replication_bootstrap_group = ON;
  mysql> START GROUP_REPLICATION USER='***', PASSWORD='***';
  mysql> SET GLOBAL group_replication_bootstrap_group = OFF;

4.3 需要知道的配置项

以下默认值都已符合集群运行的基本要求,或者不同场景,您需要不同的配置。

log_bin:二进制日志,包括所有(DDL/DML)脚本的执行记录,用于实时主从数据同步/数据恢复。

log_replica_updates:同步过来的二进制更新日志,也需要记录到自己的二进制日志中;便于灾难时的恢复。

binlog_format:数据同步日志记录的程度;一般的/更细的/混合的;当然ROW更细的日志会带来更庞大的空间占用。

[mysqld]
#log_bin = ON                        # default = ON
#log_replica_updates = ON            # default = ON
#binlog_format = ROW                 # default = ROW
#master_info_repository = TABLE      # default = TABLE
#relay_log_info_repository = TABLE   # default = TABLE

什么是 binlog

Binary Log;以二进制的形式记录了对于数据库的变更过程。
binlog可设定单文件大小,过期时间等;多用于:数据恢复、主从同步。

binlog 的三种记录方式:
STATEMENT:能够记录大多数的脚本变更过程;
ROW:记录所有的脚本变更细节,空间占用过大;
MIXED:不同方式压缩记录所有脚本的变更,确保数据的一致性、准确性。

4.4 可适当调整的扩展配置项

[mysqld]
# 持久化设置,默认=NO
# 参数或配置保存起来,如:组建时产生的账户密码,重启后依然有效
#persisted_globals_load = ON

# 选举权重百分比,默认=50,正序排列优先顺序
#loose-group_replication_member_weight = 50

# 新版 默认=MYSQL,旧版默认=XCOM
# 各节点通讯端口不可随意使用:MYSQL必须用3306,XCOM可以用33061
# group_replication_communication_stack = MYSQL

# 事务写入算法方式(组复制默认的XXHASH64,<=8.0.1版本默认值为OFF)
#transaction_write_set_extraction = XXHASH64

# 设置群组白名单,包含在内的节点才能加入
#(旧版本CommunicationStack=XCOM时有效)
#loose-group_replication_ip_whitelist="192.168.1.0/24"

# 复制单位大小;默认 150000000 字节,可适当加大以提升复制效率
#loose-group_replication_transaction_size_limit = 1500000000

# 数据复制时,外键级联检测;本次测试不需要那么严谨,默认=OFF
#loose-group_replication_enforce_update_everywhere_checks = OFF

# 为创建 InnoDB Cluster,所要屏蔽的库表类型,默认值如下
#disabled_storage_engines = "MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"

以上 cnf 中绝大多数的配置项,在后续 shell 管理集群时,都会有对应的参数设置,以覆盖 cnf 原有配置

五、mysql-shell 组建 MySQL 集群

5.1 准备各节点配置文件

这里以[4.1 必须配置项]为模板,分别创建三个 cnf 配置文件:mc1.cnfmc2.cnfmc3.cnf

后续容器启动时,分别对应各自节点的 cnf 文件。各 cnf 唯一不同的配置项是server_id

5.2 docker 启动多个SQL实例容器

这里假设三个SQL实例(集群至少),用 docker container 启动运行起来。

运行容器为集群必要的绑定项

    • 指定计算机名
    • 指定固定 IP
    • 指定同一 hosts 文件(为确保 hostname 的识别)
    • 指定各节点的 cnf 配置文件

以下唯一不同的是:hostname、ip、container-name、cnf 项。

# 第一个SQL容器的启动
docker run -dit \
    --restart unless-stopped \        # 非人为宕机后自动重启
    -e LANG=C.utf8 \                  # 设定系统字符集
    -e TZ=Asia/Shanghai \             # 设定系统时区
    -e MYSQL_ROOT_PASSWORD=sa. \      # SQL实例 root 密码
    --network br.mysql.clus \         # 使用的网路名称(自定义创建的网络)
    --ip 12.12.0.1 \                  # 指定 IP,集群模式建议固定 IP
    --name mysql.clus.n1 \            # 容器名称
    --hostname mc1 \                  # 容器内计算机名称(用以集群内的节点通讯)
    -v /etc/hosts:/etc/hosts \        # 统一 hosts 配置
    -v /my/mc1.cnf:/etc/my.cnf \      # 各实例的配置文件
    mysql:8.0.31
# 第二个SQL容器的启动
docker run -dit \
    --restart unless-stopped \
    -e LANG=C.utf8 -e TZ=Asia/Shanghai \
    -e MYSQL_ROOT_PASSWORD=sa. \
    --network br.mysql.clus --ip 12.12.0.2 \
    --name mysql.clus.n2 --hostname mc2 \
    -v /etc/hosts:/etc/hosts \
    -v /my/mc2.cnf:/etc/my.cnf \
    mysql:8.0.31
# 第三个SQL容器的启动
docker run -dit \
    --restart unless-stopped \
    -e LANG=C.utf8 -e TZ=Asia/Shanghai \
    -e MYSQL_ROOT_PASSWORD=sa. \
    --network br.mysql.clus --ip 12.12.0.3 \
    --name mysql.clus.n3 --hostname mc3 \
    -v /etc/hosts:/etc/hosts \
    -v /my/mc3.cnf:/etc/my.cnf \
    mysql:8.0.31

记住以上三个容器的SQL镜像提供的环境变量 MYSQL_ROOT_PASSWORD,也就是给 SQL Instance 的 root 设置密码为 sa.;在后续的过程当中,都以 root 及这样的密码作为凭证。

集群三个节点容器运行效果,这里把各自节点容器名称分别为:
mysql.clus.n1
mysql.clus.n2
mysql.clus.n3

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

5.3 mysql-shell 介绍

作为集群节点的管理工具,安装在任意(Win/Linux)网络互通的系统都可以,这里用官网提供的 [MySQL Yum Repository] 的方式安装到 Linux VM

可参考官网:https://dev.mysql.com/doc/mysql-yum-repo-quick-guide/en/

# MySQL Yum Repository 安装到 Linux 系统中
dnf install https://repo.mysql.com/mysql80-community-release-el9-1.noarch.rpm -y
dnf clean all && dnf makecache
# 在 Repository 中搜索以 mysql-shell 为前缀的应用
dnf list mysql-shell*
# 安装特定版本的 mysql-shell
dnf install -y mysql-shell-8.0.31

这里已经安装过,截图仅是搜索并安装的示例:

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

安装完成后,进入 mysql-shell 命令行请输入:mysqlsh

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

mysql-shell 提供了三种命令模式:JavaScript / python / sql;默认为 js 模式。

这里说明一下接下来常用到的 mysqlsh 命令:

全局对象 说明
dba 用于集群的管理
mysql SQL服务连接对象
shell 通用函数
os 与系统有关的操作
util 工具函数
shell 通用命令 说明
\? ; \help 获得帮助
\js ; \py ; \sql 切换模式
\ 多行命令
\c ; \connect {user}:{host}:{port} 连接到目标实例
\disconnect 断开连接会话
\reconnect 重新连接到会话
\! ; \system 执行系统脚本
\q ; \quit ; \exit 退出当前会话(mysql-shell)

在接下来的过程当中,经常会用

\js 方式组建管理 MySQL 集群
\sql 方式查询目标实例的数据信息

5.4 MySQL AdminAPI

在 mysqlsh 中,使用 MySQL AdminAPI 提供的dba对象及函数来 检测节点/创建集群/配置集群/解散集群/重启集群 等的集群管理操作。

有关于 AdminAPI 的研究,可参考官方文档:https://dev.mysql.com/doc/mysql-shell/8.0/en/admin-api-userguide.html

接下来以dba对象为主的集群管理操作。

5.5 检测节点实例

前期,已经运行了三个MySQL容器,参考[5.2 docker 启动多个SQL实例容器],并且配置了运行集群的必要参数;但在创建集群前,通常都会检验目标实例是否符合加入集群的要求:

先连接任意一个 Instance,比如:\c root@mc1:3306(还记得 root 密码么,也许会让你输入凭证)

然后检测所有节点的配置,是否符合集群的基本运行条件(各 cnf 的必须配置项,未配好的会提醒)

# 分别检测各节点(还记得先前配置的 hosts 各名称么)
dba.checkInstanceConfiguration('root@mc1:3306');
dba.checkInstanceConfiguration('root@mc2:3306');
dba.checkInstanceConfiguration('root@mc3:3306');

过程如下截图示例:

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

如果检测失败

1、可用 \c 方式连接到目标实例后
2、再用 dba.configureLocalInstance(); 方法引导完成必须的配置

5.6 创建集群

# 在任意目标实例中,创建名为 clus-1 的集群
# 那么,当前实例会被作为 Master 角色存在
var clus = dba.createCluster('clus-1');
# 或者,也可以指定目标实例名称,创建集群
# 如:dba.createCluster('clus-1',{localAddress:'root@mc2:3306'});
# 还记得名为 group_replication_local_address 的配置参数么,所以以上 localAddress 的值会覆盖此参数值
#
# 集群创建完成后,可用 status(); 函数查看当前集群状态信息
clus.status();
#
# 也可以获取当前节点所处的集群
var clus1 = dba.getCluster();

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

从上图可以看出:此节点为集群的主节点、可读可写、单主多从模式、集群内部通讯地址为 mc1:3306。

5.7 加入新节点

加入节点,需要设定数据恢复(与主节点保持一致)的方式:克隆、增量、自动。

可以加参数指明方式;也可以在新增过程中按系统提示选择。

# 加入新的集群节点,过程中通常选择 Clone 模式来复制主节点的数据
clus.addInstance('root@mc2:3306');
clus.addInstance('root@mc3:3306');
# 当然也有提醒信息;
# 比如:clus.addInstance('root@mc2:3306',{localAddress:'root@mc2:3306'});
# 追加的 localAddress 参数,更明确的指出此节点对集群的通讯地址
# 所以也可省略的参数,mysqlsh 也可自动取实例 Uri 作为 localAddress 参数值
#
# 此时再 .status() 查看集群状态
clus.status();

集群添加新节点图例:

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

集群 .status() 状态信息图例:

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

... ... 加入更多的节点;单主多从的集群创建完成。

节点自动连接到集群

当因为连接超时或性能压力等,被自动踢出集群的节点,恢复后自动连接到集群;
或人为修复故障后,可以手动通过 rejoinInstance() 函数再次连接到集群中;
被 removeInstance() 的节点恢复正常后,通过 addInstance() 再次加入集群。

5.8 常用集群管理函数

全局函数 说明
dba.configureLocalInstance(); 配置当前节点为符合集群的要求,不符合的配置项会自动提示。
dba.checkInstanceState({Uri}); 检查节点配置,列出节点的当前具体情况(冲突/分歧/错误)。
dba.configureInstance({Uri}, { option:value }); 配置远程SQL实例节点参数。
dba.checkInstanceConfiguration({Uri}); 检查指定节点是否符合加入集群的要求。
dba.createCluster({cluster-name}); 以指定(默认:当前)节点上下文为基准,创建一个集群。
dba.getCluster({cluster-name}); 取得当前节点所处/参数指定的集群对象。
dba.rebootClusterFromCompleteOutage({cluster-name}); 重启指定的集群(建议先 check 各节点)
dba.dropMetadataSchema(); 删除整个 Schema(无法恢复)。
当前集群对象函数 说明
{cluster}.addInstance({Uri}); 集群加入新节点。
{cluster}.status(); 集群状态信息。
{cluster}.describe(); 集群结构信息。
{cluster}.removeInstance({Uri}); 集群内移除指定的节点实例。
{cluster}.rescan(); (属于集群)列出未运行在集群内的节点实例。
{cluster}.rejoinInstance({Uri}); (故障节点修复后)重新连接到集群。
{cluster}.foreQuorumUsingPartitionOf({Uri}); 恢复集群(建议先 check 各节点)
{cluster}.dissolve(); 解散集群(各节点数据保持现状)。
{cluster}.help({fun-name}); 帮助;所有函数 或 指定函数。
{cluster}.options(); 列出此集群可配参数。
{cluster}.setOption({option}, {value}); 为此集群设定配置项。
{cluster}.setInstanceOption({Uri}, { option:value }); 为此集群的指定节点实例,设定配置项。
{cluster}.listRouters(); 查看路由信息
{cluster}.setupAdminAccount({account-name}); 为集群中的所有节点统一创建相同的账户高权限及密码(替代root)。
{cluster}.setupRouterAccount({account-name}); 为集群中的路由统一创建相同的账户高权限及密码(替代root)。

函数应用场景案例:重启集群

可能预先要做的准备工作:在集群中寻找数据集更接近完善的节点,以作为 Master 节点。

    • 生成集群节点报告,从中做出最佳选择:dba.rebootClusterFromCompleteOutage({ dryRun : true });
    • 依次连接到每个SQL实例,并执行脚本后对比GTID事务量:show variables like '%gtid_executed%';

参数应用场景案例:节点异常时踢出集群前的延迟时长

当某个节点异常时,系统会有5秒的检测时长,之后还会有延迟时长,后踢出集群;为了防止被误踢,延迟时长可配。

    • 比如在首次加入集群时设定参数:{cluster}.addInstance({Uri},{ expelTimeout : 8 });
    • 再比如非首次的后续设定方式:{cluster}.setInstanceOption({Uri},{expelTimeout:8});

那,,,mysql-shell 管理的集群有哪些参数可以设定的呢?

{cluster}.options();函数列出每个节点的所有可设置参数:(截取部分)

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

有没有熟悉的参数。。。

这里 options 所有的参数都与 cnf 配置文件参数一一对应;

比如:可以用dba.createCluster('{Uri}',{ key:value, key:value ... });这样的方式附带参数

比如:可以用.addInstance('{Uri}',{ key:value, key:value ... });这样的方式附带参数

也可以用函数.setOption( option, value );这样的方式完成参数设定。

用 mysql-shell 管理集群时,默认情况下,以上都可覆盖原有(my.cnf)配置,并可持久化(my-auto.cnf)保存。

六、集群 GR 测试

6.1 GR 数据同步测试

测试场景:在 Master 节点创建库/表/数据后;查看 Slave 节点是否已同步数据。

# 在 Master 节点创建库/表/数据
\c root@mc1:3306
create database clusterdb;
create table clusterdb.emp(id bigint not null AUTO_INCREMENT,usercode VARCHAR(32) DEFAULT NULL,createtime datetime default now(),PRIMARY KEY (id));
insert into clusterdb.emp(usercode) values ('Sol'),('wang');
# 查看 Slave 节点是否已同步数据
\c root@mc2:3306
select * from clusterdb.emp;

测试结果图:主从数据同步完成

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

6.2 故障转移测试

测试场景:Master 节点制造宕机(停机),集群选举出新的 Master 节点,是否完成故障转移

1、假设的 Master 宕机:docker stop mysql.clus.n1
2、再查看集群 Master 角色所处节点。

# 连接到集群节点
mysqlsh --uri root@mc2:3306
# 查看集群节点状况
dba.getCluster().status();

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

测试结果上图:其中 mc2:3306 节点已接替 Master 角色,完成故障转移

七、创建 mysql-router 容器加入集群

docker mysql-router 镜像,官网有测试版,参考:https://hub.docker.com/r/mysql/mysql-router

既然非生产环境的稳定版,这里在容器中安装 mysql-router。

7.1 容器中部署 mysql-router

运行已有的 oraclelinux 镜像,并进入容器:

# oraclelinux 镜像运行出新容器
docker run -dit --restart unless-stopped -e LANG=C.utf8 -e TZ=Asia/Shanghai \
    --name mysql.clus.mr --hostname mr \
    --network br.mysql.clus --ip 12.12.0.5 \
    -p 6446:6446 -p 6447:6447 \
    -v /etc/hosts:/etc/hosts \
    oraclelinux:9-slim
# 进入容器
docker exec -it mysql.clus.mr bash

容器内安装 mysql-router

通常:docker 镜像的系统,只提供最基本的应用功能,最大程度的简化,是 docker image 的特点之一。
所以:以下镜像的容器内,yum/dnf 已被移除,rpm 也被简化,但仅提供了最简陋的应用安装方式 microdnf。
当然:也可以通过 microdnf 来安装上功能强大的 yum/dnf 等,以下继续使用 microdnf 方式安装应用。

# 这里使用官方提供的 Yum Repository 方式安装
curl -#O https://repo.mysql.com/mysql80-community-release-el9-1.noarch.rpm
rpm -ivh mysql80-community-release-el9-1.noarch.rpm
# 作为镜像的微型系统,当然是仅提供基本功能
# yum/dnf 都没了,当然也可以安装上,这里使用自带的 microdnf 命令安装
# 更新 Repos,为了后续更快的应用安装(多等会)
microdnf clean all && microdnf makecache
# 模糊搜索以 mysql-router 为前缀的安装包
microdnf repoquery mysql-router*
# 搜索到的包,安装指定版本;格式:{name}-{版本号}
microdnf install mysql-router-community-8.0.31 -y
# 查看安装效果
mysqlrouter -V

7.2 容器内启动 mysql-router

# 命令有多种可选参数,这里用以下方式初始化 mysql-router 实例
# 集群 Master主机的URI格式:{sql-user}:{pass}@{host}:{port}
mysqlrouter --bootstrap root:sa.@mc1:3306 --user=root --force
# 初始化后产生的配置文件可查看,或修改配置项
cat /etc/mysqlrouter/mysqlrouter.conf
# 启动后台运行实例
mysqlrouter --user=root &

7.3 或制作成 mysql-router 镜像

a、创建空文件夹,作为制作镜像的根目录;

b、文件夹中创建 Dockerfile 文件:touch Dockerfile

  Dockerfile 文件内容如下:

# 基于 Oracle 9 Linux 系统的依赖
FROM oraclelinux:9-slim
# 系统默认字符集
ENV LANG C.utf8
# 系统默认时区
ENV TZ Asia/Shanghai
# mysql-router 用到的集群 Master Uri 作为系统变量
# 集群 Master Uri 格式为:{user}:{pass}@{host}:{port}
ENV MASTER_URI root:sa.@mc1:3306
# 以下运行在指定账户下
USER root
# 进入系统后的默认目录
WORKDIR ~
# 制作系统所需的命令步骤
# - 网络安装MySQL官网提供的 Yum Repository,编译 mysql-router 在此 Repo 下安装
RUN rpm -ivh https://repo.mysql.com/mysql80-community-release-el9-1.noarch.rpm
RUN microdnf clean all
RUN microdnf makecache
RUN microdnf install mysql-router-community-8.0.31 -y
RUN mysqlrouter --bootstrap $MASTER_URI -u=root --force
# 对外提供 mysql-router 的读写端口
EXPOSE 6446 6447
# mysql-router 初始化 并 启动
ENTRYPOINT mysqlrouter -u=root

c、Dockerfile 文件保存退出后,在此目录下执行 build 命令,生成 image 包。

# build 格式:docker build -t {image-name}:{tag} {根目录}
docker build -t mysql/router8:1.0 .
# 查看 image list
docker image ls

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

将制作的 mysql/router8 镜像运行到容器

docker run -dit \
    --restart unless-stopped \            # 非手动关机时自动重启
    --name mysql.clus.mr \                # 容器名称
    --hostname mr \                       # 计算机名
    --network br.mysql.clus \             # 指定网络
    --ip 12.12.0.5 \                      # 集群时建议使用固定IP
    -p 6446:6446 -p 6447:6447 \           # 对外开发的端口映射
    -v /my/mr.hosts:/etc/hosts \          # 集群时的 hosts 优化
    -e MASTER_URI=root:sa.@mc2:3306 \     # 集群 Master uri 地址
    mysql/router8:1.0                     # 使用制作的镜像

实例节点 + 路由 的容器列表:

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

集群查看路由信息:listRouters()

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

所以,,,客户端在连接的时候,不同的动作连接对应的端口号。

八、集群路由测试

首先,客户端 mysql-cli 先连接到 mysql-router;

mysql-router 按集群状况,把读写动作连接到不同的集群节点上。

8.1 基于路由的 - 读写分离

8.1.1 写入端口 6446 测试

测试办法:客户端 mysql-cli 连接 mysql-router 的写入端口 6446,是否连接到 Master?

# mysql-cli 连接到 mysql-router
mysql -h mr -u root -P 6446 -p
# - 验证连接的主机(是不是 mc1)
select @@hostname, @@port;

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

上图测试结果显示:路由的 6446 端口连接到 Master,并可写入数据;测试通过

8.1.2 只读端口 6447 测试

测试办法:客户端 mysql-cli 连接 mysql-router 的只读端口 6447,是否连接到 Slave?

# mysql-cli 连接到 mysql-router
mysql -h mr -u router_newuser_1 -P 6447 -p
# - 验证连接的主机(是不是 mc2,mc3)
select @@hostname, @@port;
# - 验证数据是否已经同步到从机
select * from emp;

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

测试通过。

8.3 基于路由的 - 负载均衡

测试场景:透过路由 6447 只读端口,多次连接查询数据,是否轮询连接到不同的只读节点?

MySQL8.0 高可用集群化 · mysql-shell · mysql-router · docker · 单主多从

上图测试结果显示:多次连接只读端口,连接到了不同的只读节点;测试通过