高可用集群的基本特点
负载均衡 / 读写分离 / 故障转移
本文以此为目标,利用 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
环境架构图示例:
应用安装层次图:
三、环境准备
- 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
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
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.cnf
、mc2.cnf
、mc3.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
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
这里已经安装过,截图仅是搜索并安装的示例:
安装完成后,进入 mysql-shell 命令行请输入:mysqlsh
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');
过程如下截图示例:
如果检测失败
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();
从上图可以看出:此节点为集群的主节点、可读可写、单主多从模式、集群内部通讯地址为 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();
集群添加新节点图例:
集群 .status() 状态信息图例:
... ... 加入更多的节点;单主多从的集群创建完成。
节点自动连接到集群
当因为连接超时或性能压力等,被自动踢出集群的节点,恢复后自动连接到集群;
或人为修复故障后,可以手动通过 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();
函数列出每个节点的所有可设置参数:(截取部分)
有没有熟悉的参数。。。
这里 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;
测试结果图:主从数据同步完成。
6.2 故障转移测试
测试场景:Master 节点制造宕机(停机),集群选举出新的 Master 节点,是否完成故障转移。
1、假设的 Master 宕机:docker stop mysql.clus.n1
2、再查看集群 Master 角色所处节点。
# 连接到集群节点
mysqlsh --uri root@mc2:3306
# 查看集群节点状况
dba.getCluster().status();
测试结果上图:其中 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
将制作的 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 # 使用制作的镜像
实例节点 + 路由 的容器列表:
集群查看路由信息:listRouters()
所以,,,客户端在连接的时候,不同的动作连接对应的端口号。
八、集群路由测试
首先,客户端 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;
上图测试结果显示:路由的 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;
测试通过。
8.3 基于路由的 - 负载均衡
测试场景:透过路由 6447 只读端口,多次连接查询数据,是否轮询连接到不同的只读节点?
上图测试结果显示:多次连接只读端口,连接到了不同的只读节点;测试通过。