引言:从"手动运维"到"架构自治"的跨越**
在金融级数据库的守卫战中,开发者常面临一个极具挑战的"断层":即便后端 MySQL MGR 已经实现了秒级的 Paxos 选主和强一致性数据同步,但前端应用往往仍因 TCP 连接失效、虚 IP(VIP)切换延迟或人工配置修改,导致业务出现分钟级的震荡。对于追求 RPO = 0 与 RTO < 5s 的核心账务系统而言,这种"感知滞后"是不可接受的。
MySQL Router 的出现,正是为了填补这一断层。它不仅是一个轻量级的转发代理,更是集群拓扑的"动态导航仪"。通过实时监听 MGR 元数据变化,它能确保流量始终精准投递至健康的 Primary 节点。
本指南将跳过冗长的基础理论,直接从金融实战视角出发,带你深入剖析 Router 的实现逻辑,并在一台 RHEL 8 宿主机上,从零开始构建一套具备全透明切换能力的生产级接入层。我们将从核心概念起步,逐步进入全链路模拟演练。
1 深入理解 MySQL Router
什么是 MySQL Router?
MySQL Router 是 MySQL Innodb Cluster 架构中的轻量级中间件 。它不是 ProxySQL 那种重型插件,它不解析 SQL 语句(除非开启特定模式),其本质是一个基于状态感知的四层(TCP 层)智能转发代理。
为什么金融级架构必选 Router?
在传统的 MGR 架构中,当 Primary 节点宕机,集群会选出新主。此时,业务程序面临两个痛点:
- IP 漂移困境: 如果没有 Router,业务必须写死一个 VIP(虚拟 IP)。但在云原生或复杂网络下,VIP 切换慢、易脑裂。
- 读写分离混乱: 业务往往需要手动维护"写连接池"和"读连接池"。
MySQL Router 的解决逻辑: 它通过实时监听 MGR 的 metadata,自动维护两个端口。业务只需访问 Router 的端口,Router 负责把请求"瞬移"到正确的实例上。
核心实现逻辑:Metadata Cache
Router 内部运行着一个名为 Metadata Cache 的组件。
- 启动时: 它根据
--bootstrap提供的节点信息连接集群。 - 运行时: 它与集群保持长连接。通过查询
performance_schema.replication_group_members视图,它能实时知道谁是 PRIMARY(读写),谁是 SECONDARY(只读)。 - 故障时: 一旦 MGR 拓扑变更,Router 毫秒级更新内存路由表,并强制断开旧的失效连接,迫使应用重连到新主。
两种部署模式的区别
| 模式 | 部署位置 | 优点 | 缺点 | 建议 |
|---|---|---|---|---|
| 同机部署 (Sandbox) | 应用服务器本地 | 极低延迟,无单点故障(App 挂了 Router 才挂) | 管理节点多,每个 App 都要装 | 金融级首选 |
| 独立部署 (Standalone) | 专用中间件服务器 | 集中管理,扩容方便 | 增加一跳网络延迟,需要考虑 Router 自身高可用 | 中大型集群推荐 |
2 从零开始部署与验证
环境准备
- MGR 节点:
192.168.31.101,31.102,31.103(MySQL 8.0.45) - Router 节点:
192.168.1.13(RHEL 8) - 已有3节点MGR
sql
mysql> SELECT MEMBER_ID,MEMBER_HOST,MEMBER_PORT,MEMBER_STATE,MEMBER_ROLE,MEMBER_VERSION FROM performance_schema.replication_group_members;
+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| 6db421a2-fb59-11f0-99ab-bc24110512df | mgr-node3 | 3306 | ONLINE | SECONDARY | 8.0.45 |
| 8b4a22ea-fb59-11f0-b92c-bc2411b87e43 | mgr-node2 | 3306 | ONLINE | SECONDARY | 8.0.45 |
| 8fdf4d79-fb59-11f0-ba9c-bc24116a13f0 | mgr-node1 | 3306 | ONLINE | PRIMARY | 8.0.45 |
+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)
安装 MySQL Router
在 31.106 节点上执行:
yaml
# 1. 配置 MySQL 官方 Repo
rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el8-9.noarch.rpm
# 2. 禁用 RHEL8 自带的 mysql 模块以避免冲突
dnf -y module disable mysql
# 3. 仅安装 Router 及其依赖
dnf install -y mysql-router-community
## 安装记录如下
# rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el8-9.noarch.rpm
Retrieving https://dev.mysql.com/get/mysql80-community-release-el8-9.noarch.rpm
warning: /var/tmp/rpm-tmp.NC9vkq: Header V4 RSA/SHA256 Signature, key ID 3a79bd29: NOKEY
Verifying... ################################# [100%]
Preparing... ################################# [100%]
Updating / installing...
1:mysql80-community-release-el8-9 ################################# [100%]
Warning: native mysql package from platform vendor seems to be enabled.
Please consider to disable this before installing packages from repo.mysql.com.
Run: yum module -y disable mysql
# dnf -y module disable mysql
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Local Repository 2.7 MB/s | 2.8 kB 00:00
Local Repository 3.1 MB/s | 3.2 kB 00:00
MySQL 8.0 Community Server 736 kB/s | 5.2 MB 00:07
MySQL Connectors Community 84 kB/s | 185 kB 00:02
MySQL Tools Community 522 kB/s | 1.8 MB 00:03
Dependencies resolved.
===================================================================================================================================
Package Architecture Version Repository Size
===================================================================================================================================
Disabling modules:
mysql
Transaction Summary
===================================================================================================================================
Complete!
# dnf install -y mysql-router-community
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Last metadata expiration check: 0:00:08 ago on Wed 28 Jan 2026 03:16:45 PM CST.
Dependencies resolved.
====================================================================================================================================
Package Architecture Version Repository Size
====================================================================================================================================
Installing:
mysql-router-community x86_64 8.0.45-1.el mysql-tools-community 5.4 M
Transaction Summary
====================================================================================================================================
Install 1 Package
Total download size: 5.4 M
Installed size: 24 M
Downloading Packages:
mysql-router-community-8.0.45-1.el8.x86_64.rpm 1.3 MB/s | 5.4 MB 00:04
------------------------------------------------------------------------------------------------------------
Total 1.3 MB/s | 5.4 MB 00:04
warning: /var/cache/dnf/mysql-tools-community-9c88dbf3370d24b7/packages/mysql-router-community-8.0.45-1.el8.x86_64.rpm: Header V4 RSA/SHA256 Signature, key ID a8d3785c: NOKEY
MySQL Tools Community 3.0 MB/s | 3.1 kB 00:00
Importing GPG key 0xA8D3785C:
Userid : "MySQL Release Engineering <mysql-build@oss.oracle.com>"
Fingerprint: BCA4 3417 C3B4 85DD 128E C6D4 B7B3 B788 A8D3 785C
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql-2023
Key imported successfully
MySQL Tools Community 3.0 MB/s | 3.1 kB 00:00
Importing GPG key 0x3A79BD29:
Userid : "MySQL Release Engineering <mysql-build@oss.oracle.com>"
Fingerprint: 859B E8D7 C586 F538 430B 19C2 467B 942D 3A79 BD29
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql-2022
Key imported successfully
MySQL Tools Community 1.9 MB/s | 1.9 kB 00:00
Importing GPG key 0x5072E1F5:
Userid : "MySQL Release Engineering <mysql-build@oss.oracle.com>"
Fingerprint: A4A9 4068 76FC BD3C 4567 70C8 8C71 8D3B 5072 E1F5
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Running scriptlet: mysql-router-community-8.0.45-1.el8.x86_64 1/1
Installing : mysql-router-community-8.0.45-1.el8.x86_64 1/1
Running scriptlet: mysql-router-community-8.0.45-1.el8.x86_64 1/1
Verifying : mysql-router-community-8.0.45-1.el8.x86_64 1/1
Installed products updated.
Installed:
mysql-router-community-8.0.45-1.el8.x86_64
Complete!
数据库端权限准备
在 MGR Primary 节点创建供 Router 引导使用的管理账号:
sql
-- 创建管理账号,用于 Router 引导并读取元数据
CREATE USER 'router_admin'@'%' IDENTIFIED BY 'Financial_Pass_123';
GRANT ALL PRIVILEGES ON *.* TO 'router_admin'@'%' WITH GRANT OPTION;
-- 必须授予对 performance_schema 的读权限
GRANT SELECT ON performance_schema.* TO 'router_admin'@'%';
secondary节点创建时会报错:
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
引导配置 (Bootstrap)
- 查看mysqlrouter
bash
# rpm -ql mysql-router-community
/etc/logrotate.d/mysqlrouter
/etc/mysqlrouter
/etc/mysqlrouter/mysqlrouter.conf
/usr/bin/mysqlrouter
/usr/bin/mysqlrouter_keyring
/usr/bin/mysqlrouter_passwd
/usr/bin/mysqlrouter_plugin_info
/usr/lib/.build-id
...
/usr/lib64/mysqlrouter/routing.so
/usr/share/doc/mysql-router-community
/usr/share/doc/mysql-router-community/INFO_BIN
/usr/share/doc/mysql-router-community/INFO_SRC
/usr/share/doc/mysql-router-community/LICENSE.router
/usr/share/doc/mysql-router-community/README.router
/usr/share/man/man1/mysqlrouter.1.gz
/usr/share/man/man1/mysqlrouter_passwd.1.gz
/usr/share/man/man1/mysqlrouter_plugin_info.1.gz
/var/log/mysqlrouter
/var/run/mysqlrouter
# which mysqlrouter
/usr/bin/mysqlrouter
# mysqlrouter --version
MySQL Router Ver 8.0.45 for Linux on x86_64 (MySQL Community - GPL)
# id mysqlrouter
uid=994(mysqlrouter) gid=991(mysqlrouter) groups=991(mysqlrouter)
- 默认配置
ini
# cat /etc/mysqlrouter/mysqlrouter.conf
# Copyright (c) 2015, 2025, Oracle and/or its affiliates.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is designed to work with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms,
# as designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have either included with
# the program or referenced in the documentation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# MySQL Router configuration file
#
# Documentation is available at
# http://dev.mysql.com/doc/mysql-router/en/
[DEFAULT]
logging_folder = /var/log/mysqlrouter
runtime_folder = /run/mysqlrouter
config_folder = /etc/mysqlrouter
[logger]
level = INFO
# If no plugin is configured which starts a service, keepalive
# will make sure MySQL Router will not immediately exit. It is
# safe to remove once Router is configured.
[keepalive]
interval = 60
这是最关键的一步,我们采用分离式目录部署,互不干扰。
ini
## 创建目录
mkdir -p /etc/mysqlrouter/finance_instance
## 初始化
mysqlrouter --bootstrap router_admin@192.168.31.101:3306 \
--user=mysqlrouter \
--directory=/etc/mysqlrouter/finance_instance \
--conf-use-sockets \
--force
简单来说,这个命令的作用是:让 Router 去"认领"这个 MGR 集群,并自动给自己写好配置文件。
| 参数 | 含义与老兵解读 |
|---|---|
| --bootstrap | 引导模式。这是 Router 最聪明的模式。它会登录到你指定的数据库,读取 MGR 的拓扑结构、UUID、角色等信息,并自动生成 mysqlrouter.conf。 |
| router_admin@...:3306 | 认证信息。Router 用这个账号登录数据库(任何一个节点均可)。建议使用专门的 router_admin 账号(需具备 SELECT 权限于 performance_schema)。 |
| --user=mysqlrouter | 运行用户。指定 Router 进程在 RHEL 8 系统中以哪个 Linux 用户身份运行。为了安全,严禁使用 root。 |
| --directory | 实例目录。这是最佳实践。它会把所有的配置、日志、PID 文件、甚至启动/停止脚本都放在这个目录下。实现"一个目录就是一个 Router 实例",非常利于运维。 |
| --conf-use-sockets | 开启 Socket 连接。如果 Router 部署在数据库本机,它会尝试用 Unix Domain Socket,延迟比 TCP 更低。但在你这种独立部署模式下,它主要作为一种备份配置生成。 |
| --force | 强制覆盖。如果目录里已经有了旧配置,它会直接覆盖。在反复调试环境时非常有用。 |
专家建议: 使用 --directory 参数可以将配置文件、日志、Key 全部隔离。
运行时出现了报错
Please enter MySQL password for router_admin: Error: Expected MySQL Server '192.168.31.101:3306' to contain the metadata of MySQL InnoDB Cluster, but the schema does not exist. Checking version of the metadata schema failed with: Error executing MySQL query "SELECT * FROM mysql_innodb_cluster_metadata.schema_version": Unknown database 'mysql_innodb_cluster_metadata' (1049)
解释:由于MGR 是用原生的 SQL 命令(如
START GROUP_REPLICATION)搭建的,这在内核层面是没问题的。mysqlrouter --bootstrap命令不仅是去连数据库,它还要求数据库里必须有一套由 MySQL Shell 创建的元数据表。Router 就像一个查岗的哨兵,它去 101 查岗,结果发现 101 根本没有"岗位签到簿"(即mysql_innodb_cluster_metadata库)。
要解决这个问题,你不需要重装 MGR,只需要用 MySQL Shell 把你现有的 3 节点 MGR "收编" 一下。当然 如果你真的不想在数据库里装任何"补丁",那我们就放弃--bootstrap。这是老一代 DBA 的做法,虽然繁琐,但透明。直接创建配置文件进行手动编辑: vi /etc/mysqlrouter/mysqlrouter.conf
老兵建议: 在金融生产环境下,必须使用 Bootstrap 模式。因为一旦你手动写死配置,未来 MGR 扩容、缩容或换 IP,Router 都不会自动感应,这会导致你半夜被迫起床修配置。
- 106上安装 MySQL Shell
sql
dnf install -y mysql-shell
# 安装日志
# dnf install -y mysql-shell
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Last metadata expiration check: 1:19:24 ago on Wed 28 Jan 2026 03:16:45 PM CST.
Dependencies resolved.
=======================================================================================================================================
Package Architecture Version Repository Size
=======================================================================================================================================
Installing:
mysql-shell x86_64 8.0.45-1.el8 mysql-tools-community 90 M
Transaction Summary
=======================================================================================================================================
Install 1 Package
Total download size: 90 M
Installed size: 469 M
Downloading Packages:
mysql-shell-8.0.45-1.el8.x86_64.rpm 3.3 MB/s | 90 MB 00:27
------------------------------------------------------------------------------------------------------------
Total 3.3 MB/s | 90 MB 00:27
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : mysql-shell-8.0.45-1.el8.x86_64 1/1
Running scriptlet: mysql-shell-8.0.45-1.el8.x86_64 1/1
Verifying : mysql-shell-8.0.45-1.el8.x86_64 1/1
Installed products updated.
Installed:
mysql-shell-8.0.45-1.el8.x86_64
Complete!
# mysqlsh --version
WARNING: Permissions 0644 for log file "/root/.mysqlsh/mysqlsh.log" are too open. Permissions have been adjusted for user only access.
mysqlsh Ver 8.0.45 for Linux on x86_64 - for MySQL 8.0.45 (MySQL Community Server (GPL)
- 106上添加主机名
bash
cat >> /etc/hosts << EOF
192.168.31.101 mgr-node1
192.168.31.102 mgr-node2
192.168.31.103 mgr-node3
EOF
- 通过 MySQL Shell 连接 101 节点
arduino
mysqlsh --uri router_admin@192.168.31.101:3306
# mysqlsh --uri router_admin@192.168.31.101:3306
Please provide the password for 'router_admin@192.168.31.101:3306': ******************
Save password for 'router_admin@192.168.31.101:3306'? [Y]es/[N]o/Ne[v]er (default No): Y
MySQL Shell 8.0.45
Copyright (c) 2016, 2026, 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 '?' for help; '\quit' to exit.
Creating a Classic session to 'router_admin@192.168.31.101:3306'
Fetching schema names for auto-completion... Press ^C to stop.
Your MySQL connection id is 65
Server version: 8.0.45 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.
MySQL 192.168.31.101:3306 ssl JS >
- 执行"收编"操作(核心步骤) 在 MySQL Shell 的 JS 模式下(默认就是),执行以下命令:
csharp
// 1. 获取现有集群对象,执行此命令会提示:这个集群不是由 Shell 创建的,是否纳管?
var cluster = dba.getCluster();
// 2. 如果上面报错,使用下面这行强制"收编"现有的 MGR 集群
var cluster = dba.createCluster('finance_cluster', {adoptFromGR: true});
// 3. 检查状态
cluster.status();
//结果如下
MySQL 192.168.31.101:3306 ssl JS > var cluster = dba.createCluster('finance_cluster', {adoptFromGR: true});
A new InnoDB Cluster will be created based on the existing replication group on instance 'mgr-node1:3306'.
Creating InnoDB Cluster 'finance_cluster' on 'mgr-node1:3306'...
Adding Seed Instance...
Adding Instance 'mgr-node3:3306'...
Adding Instance 'mgr-node2:3306'...
Adding Instance 'mgr-node1:3306'...
Resetting distributed recovery credentials across the cluster...
Cluster successfully created based on existing replication group.
MySQL 192.168.31.101:3306 ssl JS > cluster.status();
{
"clusterName": "finance_cluster",
"defaultReplicaSet": {
"name": "default",
"primary": "mgr-node1:3306",
"ssl": "DISABLED",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"mgr-node1:3306": {
"address": "mgr-node1:3306",
"instanceErrors": [
"NOTE: The required parallel-appliers settings are not enabled on the instance. Use dba.configureInstance() to fix it."
],
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.0.45"
},
"mgr-node2:3306": {
"address": "mgr-node2:3306",
"instanceErrors": [
"NOTE: The required parallel-appliers settings are not enabled on the instance. Use dba.configureInstance() to fix it."
],
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.0.45"
},
"mgr-node3:3306": {
"address": "mgr-node3:3306",
"instanceErrors": [
"NOTE: The required parallel-appliers settings are not enabled on the instance. Use dba.configureInstance() to fix it."
],
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.0.45"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "mgr-node1:3306"
}
MySQL 192.168.31.101:3306 ssl JS >
MySQL 192.168.31.101:3306 ssl JS > \q
Bye!
注:finance_cluster 是你给集群起的名字。执行完这一步后,MySQL Shell 会自动在你的数据库里创建 mysql_innodb_cluster_metadata 这个库。
- 数据库中查看数据库
mysql_innodb_cluster_metadata
sql
mysql> use mysql_innodb_cluster_metadata;
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> show tables;
+-----------------------------------------+
| Tables_in_mysql_innodb_cluster_metadata |
+-----------------------------------------+
| async_cluster_members |
| async_cluster_views |
| clusters |
| clusterset_members |
| clusterset_views |
| clustersets |
| instances |
| router_rest_accounts |
| routers |
| schema_version |
| v2_ar_clusters |
| v2_ar_members |
| v2_clusters |
| v2_cs_clustersets |
| v2_cs_members |
| v2_cs_router_options |
| v2_gr_clusters |
| v2_instances |
| v2_router_rest_accounts |
| v2_routers |
| v2_this_instance |
+-----------------------------------------+
21 rows in set (0.01 sec)
- 再次执行 Bootstrap
css
# mysqlrouter --bootstrap router_admin@192.168.31.101:3306 \
> --user=mysqlrouter \
> --directory=/etc/mysqlrouter/finance_instance \
> --conf-use-sockets \
> --force
Please enter MySQL password for router_admin:
# Bootstrapping MySQL Router 8.0.45 (MySQL Community - GPL) instance at '/etc/mysqlrouter/finance_instance'...
- Creating account(s) (only those that are needed, if any)
- Verifying account (using it to run SQL queries that would be run by Router)
- Storing account in keyring
- Adjusting permissions of generated files
- Creating configuration /etc/mysqlrouter/finance_instance/mysqlrouter.conf
# MySQL Router configured for the InnoDB Cluster 'finance_cluster'
After this MySQL Router has been started with the generated configuration
$ mysqlrouter -c /etc/mysqlrouter/finance_instance/mysqlrouter.conf
InnoDB Cluster 'finance_cluster' can be reached by connecting to:
## MySQL Classic protocol
- Read/Write Connections: localhost:6446, /etc/mysqlrouter/finance_instance/mysql.sock
- Read/Only Connections: localhost:6447, /etc/mysqlrouter/finance_instance/mysqlro.sock
## MySQL X protocol
- Read/Write Connections: localhost:6448, /etc/mysqlrouter/finance_instance/mysqlx.sock
- Read/Only Connections: localhost:6449, /etc/mysqlrouter/finance_instance/mysqlxro.sock
- 查看生成的配置文件
ini
[root@rhel82-node106 ~]# ls -l /etc/mysqlrouter/finance_instance/
total 16
drwx------ 2 mysqlrouter mysqlrouter 116 Jan 28 20:34 data
drwx------ 2 mysqlrouter mysqlrouter 29 Jan 28 20:34 log
-rw------- 1 mysqlrouter mysqlrouter 2329 Jan 28 20:34 mysqlrouter.conf
-rw------- 1 mysqlrouter mysqlrouter 104 Jan 28 20:34 mysqlrouter.key
drwx------ 2 mysqlrouter mysqlrouter 6 Jan 28 20:34 run
-rwx------ 1 mysqlrouter mysqlrouter 315 Jan 28 20:34 start.sh
-rwx------ 1 mysqlrouter mysqlrouter 209 Jan 28 20:34 stop.sh
[root@rhel82-node106 ~]# cat /etc/mysqlrouter/finance_instance/mysqlrouter.conf
# File automatically generated during MySQL Router bootstrap
[DEFAULT]
user=mysqlrouter
logging_folder=/etc/mysqlrouter/finance_instance/log
runtime_folder=/etc/mysqlrouter/finance_instance/run
data_folder=/etc/mysqlrouter/finance_instance/data
keyring_path=/etc/mysqlrouter/finance_instance/data/keyring
master_key_path=/etc/mysqlrouter/finance_instance/mysqlrouter.key
connect_timeout=5
read_timeout=30
dynamic_state=/etc/mysqlrouter/finance_instance/data/state.json
client_ssl_cert=/etc/mysqlrouter/finance_instance/data/router-cert.pem
client_ssl_key=/etc/mysqlrouter/finance_instance/data/router-key.pem
client_ssl_mode=PREFERRED
server_ssl_mode=AS_CLIENT
server_ssl_verify=DISABLED
unknown_config_option=error
[logger]
level=INFO
[metadata_cache:bootstrap]
cluster_type=gr
router_id=1
user=mysql_router1_gbf0w3y
metadata_cluster=finance_cluster
ttl=0.5
auth_cache_ttl=-1
auth_cache_refresh_interval=2
use_gr_notifications=0
[routing:bootstrap_rw]
bind_address=0.0.0.0
bind_port=6446
socket=/etc/mysqlrouter/finance_instance/mysql.sock
destinations=metadata-cache://finance_cluster/?role=PRIMARY
routing_strategy=first-available
protocol=classic
[routing:bootstrap_ro]
bind_address=0.0.0.0
bind_port=6447
socket=/etc/mysqlrouter/finance_instance/mysqlro.sock
destinations=metadata-cache://finance_cluster/?role=SECONDARY
routing_strategy=round-robin-with-fallback
protocol=classic
[routing:bootstrap_x_rw]
bind_address=0.0.0.0
bind_port=6448
socket=/etc/mysqlrouter/finance_instance/mysqlx.sock
destinations=metadata-cache://finance_cluster/?role=PRIMARY
routing_strategy=first-available
protocol=x
[routing:bootstrap_x_ro]
bind_address=0.0.0.0
bind_port=6449
socket=/etc/mysqlrouter/finance_instance/mysqlxro.sock
destinations=metadata-cache://finance_cluster/?role=SECONDARY
routing_strategy=round-robin-with-fallback
protocol=x
[http_server]
port=8443
ssl=1
ssl_cert=/etc/mysqlrouter/finance_instance/data/router-cert.pem
ssl_key=/etc/mysqlrouter/finance_instance/data/router-key.pem
[http_auth_realm:default_auth_realm]
backend=default_auth_backend
method=basic
name=default_realm
[rest_router]
require_realm=default_auth_realm
[rest_api]
[http_auth_backend:default_auth_backend]
backend=metadata_cache
[rest_routing]
require_realm=default_auth_realm
[rest_metadata_cache]
require_realm=default_auth_realm
- 在配置文件中,你会看到
protocol=classic和protocol=x两种协议,每种协议又分 RW(读写)和 RO(只读)。
| 端口 | 模块名称 | 协议类型 | 角色定位 | 业务用途 |
|---|---|---|---|---|
| 6446 | bootstrap_rw | Classic | Primary | 核心写入端口。所有增删改操作(Java/Go JDBC)都连这里。 |
| 6447 | bootstrap_ro | Classic | Secondary | 只读端口。报表、查询连这里,它会在从节点间做负载均衡。 |
| 6448 | bootstrap_x_rw | X Protocol | Primary | NoSQL/文档存储写入。如果你用 MySQL 当 MongoDB 用(X DevAPI),走这里。 |
| 6449 | bootstrap_x_ro | X Protocol | Secondary | NoSQL/文档存储只读。 |
剩下的两个端口是 Router 自身的管理窗口:
- 8443 (HTTPS): * 它是 Router 的 REST API 端口。 你可以通过 HTTP 请求获取 Router 的运行状态、连接数、内存占用等。它是对接 Prometheus 或 Zabbix 监控的"生命线"。
- Unix Sockets (mysql.sock): 虽然没占用 TCP 端口,但你会发现
socket配置。 它的作用是让同机部署的应用不需要通过网络栈,直接读写文件进行通讯,进一步压低延迟。
启动与验证
bash
# 查看启动脚本
# cat /etc/mysqlrouter/finance_instance/start.sh
#!/bin/bash
basedir=/etc/mysqlrouter/finance_instance
if [ `whoami` == 'mysqlrouter' ]; then
ROUTER_PID=$basedir/mysqlrouter.pid /usr/bin/mysqlrouter -c $basedir/mysqlrouter.conf &
else
sudo ROUTER_PID=$basedir/mysqlrouter.pid /usr/bin/mysqlrouter -c $basedir/mysqlrouter.conf --user=mysqlrouter &
fi
disown %-
# 启动 Router 实例
/etc/mysqlrouter/finance_instance/start.sh
# /etc/mysqlrouter/finance_instance/start.sh
PID 14153 written to '/etc/mysqlrouter/finance_instance/mysqlrouter.pid'
stopping to log to the console. Continuing to log to filelog
# 检查端口监听情况 dfn install net-tools可以安装netstat命令
netstat -lnpt | grep mysqlrouter
# netstat -lnpt | grep mysqlrouter
tcp 0 0 0.0.0.0:6447 0.0.0.0:* LISTEN 14153/mysqlrouter
tcp 0 0 0.0.0.0:6448 0.0.0.0:* LISTEN 14153/mysqlrouter
tcp 0 0 0.0.0.0:6449 0.0.0.0:* LISTEN 14153/mysqlrouter
tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN 14153/mysqlrouter
tcp 0 0 0.0.0.0:6446 0.0.0.0:* LISTEN 14153/mysqlrouter
连通性测试
现在 Router 已经起来了,你可以用最原始的客户端在第 4 台机器上测试一下:
sql
# 测试写端口(应该连到 101)
mysql -u router_admin -p'Financial_Pass_123' -h 127.0.0.1 -P 6446 -e "select @@hostname;"
# 测试读端口(多次执行,应该在 102 和 103 之间跳动)
mysql -u router_admin -p -h 127.0.0.1 -P 6447 -e "select @@hostname;"
[root@rhel82-node106 ~]# mysql -u router_admin -p'Financial_Pass_123' -h 127.0.0.1 -P 6446 -e "select @@hostname;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mgr-node1 |
+------------+
[root@rhel82-node106 ~]# mysql -u router_admin -p'Financial_Pass_123' -h 127.0.0.1 -P 6447 -e "select @@hostname;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mgr-node3 |
+------------+
[root@rhel82-node106 ~]# mysql -u router_admin -p'Financial_Pass_123' -h 127.0.0.1 -P 6447 -e "select @@hostname;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| mgr-node2 |
+------------+
你的 Router 现在已经完全跑通了!
3 Java 程序实现与库表准备
数据库数据准备
sql
CREATE DATABASE finance_db;
USE finance_db;
CREATE TABLE t_balance (
id INT PRIMARY KEY,
account_name VARCHAR(50),
balance DECIMAL(15,2),
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB;
INSERT INTO t_balance (id, account_name, balance) VALUES (1, 'Gemini_User', 10000.00);
-- 创建业务账号
CREATE USER 'biz_user'@'%' IDENTIFIED BY 'Biz_Pass_456';
GRANT SELECT, INSERT, UPDATE, DELETE ON finance_db.* TO 'biz_user'@'%';
准备项目结构
在你的 RHEL 8 或开发机上,创建一个专门的项目文件夹:
bash
mkdir -p finance-test/src/main/java
cd finance-test
编写 pom.xml (Maven 项目核心)
创建一个名为 pom.xml 的文件。它负责自动下载 HikariCP (目前性能最强、金融业最常用的连接池)和 MySQL 驱动。
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.finance</groupId>
<artifactId>router-test</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
</project>
编写 FinanceApp.java
在 src/main/java 目录下创建 FinanceApp.java。
专家提醒: 这里的 jdbcUrl 必须指向 Router 所在的 IP 和 6446 端口 。如果程序就在 Router 那台机器跑,写 127.0.0.1 性能最好。
java
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.*;
public class FinanceApp {
public static void main(String[] args) {
HikariConfig config = new HikariConfig();
// 关键点:连接 Router 的写端口 6446
config.setJdbcUrl("jdbc:mysql://192.168.31.106:6446/finance_db?useSSL=false&allowPublicKeyRetrieval=true");
config.setUsername("biz_user");
config.setPassword("Biz_Pass_456");
// --- 金融级稳定性参数 ---
config.setConnectionTimeout(2000); // 2秒连不上立刻报错,不要卡死应用
config.setValidationTimeout(1000); // 验证连接是否有效的超市
config.setMaximumPoolSize(10); // 保持 10 个长连接
config.setMinimumIdle(5); // 最少保持 5 个闲置连接
HikariDataSource ds = new HikariDataSource(config);
System.out.println(">>> 正在启动金融交易模拟测试...");
// 模拟一个死循环写入,每秒一次,用来观察主从切换时的现象
while (true) {
long startTime = System.currentTimeMillis();
try (Connection conn = ds.getConnection()) {
// 1. 查询当前连接到了哪台物理机
String hostname = "unknown";
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT @@hostname")) {
if (rs.next()) hostname = rs.getString(1);
}
// 2. 执行一次模拟扣款写入
String sql = "UPDATE t_balance SET balance = balance + 0.01 WHERE id = 1";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.executeUpdate();
}
long cost = System.currentTimeMillis() - startTime;
System.out.printf("[SUCCESS] 写入耗时: %dms | 当前数据库节点: %s\n", cost, hostname);
} catch (SQLException e) {
// 当 MGR 切换主节点时,这里会抓到错误
System.err.println("[ERROR] 业务瞬间中断: " + e.getMessage());
}
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
}
}
编译与执行
在 RHEL 8 上,确保你安装了 Maven(dnf install -y maven)。
yaml
## 安装日志
# mount /dev/sr0 /mnt
mount: /mnt: WARNING: device write-protected, mounted read-only.
[root@rhel82-node106 finance-test]# dnf install -y maven
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Last metadata expiration check: 17:35:41 ago on Wed 28 Jan 2026 08:25:51 PM CST.
Dependencies resolved.
=====================================================================================================================================
Package Architecture Version Repository Size
=====================================================================================================================================
Installing:
maven noarch 1:3.5.4-5.module+el8+2452+b359bfcd local-AppStream 27 k
Installing dependencies:
alsa-lib x86_64 1.2.1.2-3.el8 local-AppStream 441 k
aopalliance noarch 1.0-17.module+el8+2452+b359bfcd local-AppStream 17 k
apache-commons-cli noarch 1.4-4.module+el8+2452+b359bfcd local-AppStream 74 k
apache-commons-codec noarch 1.11-3.module+el8+2452+b359bfcd local-AppStream 288 k
apache-commons-io noarch 1:2.6-3.module+el8+2452+b359bfcd local-AppStream 224 k
apache-commons-lang3 noarch 3.7-3.module+el8+2452+b359bfcd local-AppStream 483 k
apache-commons-logging noarch 1.2-13.module+el8+2452+b359bfcd local-AppStream 85 k
atinject noarch 1-28.20100611svn86.module+el8+2452+b359bfcd local-AppStream 20 k
atk x86_64 2.28.1-1.el8 local-AppStream 272 k
avahi-libs x86_64 0.7-19.el8 local 63 k
cairo x86_64 1.15.12-3.el8 local-AppStream 721 k
cdi-api noarch 1.2-8.module+el8+2452+b359bfcd local-AppStream 70 k
...
libXrender x86_64 0.9.10-7.el8 local-AppStream 33 k
libXtst x86_64 1.2.3-7.el8 local-AppStream 22 k
libdatrie x86_64 0.2.9-7.el8 local-AppStream 33 k
libfontenc x86_64 1.1.3-8.el8 local-AppStream 37 k
libjpeg-turbo x86_64 1.5.3-10.el8 local-AppStream 156 k
libthai x86_64 0.1.27-2.el8 local-AppStream 203 k
libtiff x86_64 4.0.9-17.el8 local-AppStream 188 k
libxcb x86_64 1.13.1-1.el8 local-AppStream 229 k
lksctp-tools x86_64 1.0.18-3.el8 local 100 k
lua x86_64 5.3.4-11.el8 local-AppStream 193 k
maven-lib noarch 1:3.5.4-5.module+el8+2452+b359bfcd local-AppStream 1.4 M
maven-resolver-api noarch 1:1.1.1-2.module+el8+2452+b359bfcd local-AppStream 138 k
maven-resolver-connector-basic noarch 1:1.1.1-2.module+el8+2452+b359bfcd local-AppStream 51 k
maven-resolver-impl noarch 1:1.1.1-2.module+el8+2452+b359bfcd local-AppStream 177 k
maven-resolver-spi noarch 1:1.1.1-2.module+el8+2452+b359bfcd local-AppStream 40 k
maven-resolver-transport-wagon noarch 1:1.1.1-2.module+el8+2452+b359bfcd local-AppStream 39 k
maven-resolver-util noarch 1:1.1.1-2.module+el8+2452+b359bfcd local-AppStream 148 k
maven-shared-utils noarch 3.2.1-0.1.module+el8+2452+b359bfcd local-AppStream 165 k
maven-wagon-file noarch 3.1.0-1.module+el8+2452+b359bfcd local-AppStream 26 k
maven-wagon-http noarch 3.1.0-1.module+el8+2452+b359bfcd local-AppStream 27 k
maven-wagon-http-shared noarch 3.1.0-1.module+el8+2452+b359bfcd local-AppStream 49 k
maven-wagon-provider-api noarch 3.1.0-1.module+el8+2452+b359bfcd local-AppStream 63 k
pango x86_64 1.42.4-6.el8 local-AppStream 298 k
pixman x86_64 0.38.4-1.el8 local-AppStream 257 k
plexus-cipher noarch 1.7-14.module+el8+2452+b359bfcd local-AppStream 29 k
plexus-classworlds noarch 2.5.2-9.module+el8+2452+b359bfcd local-AppStream 65 k
plexus-containers-component-annotations noarch 1.7.1-8.module+el8+2452+b359bfcd local-AppStream 24 k
plexus-interpolation noarch 1.22-9.module+el8+2452+b359bfcd local-AppStream 79 k
plexus-sec-dispatcher noarch 1.4-26.module+el8+2452+b359bfcd local-AppStream 37 k
plexus-utils noarch 3.1.0-3.module+el8+2452+b359bfcd local-AppStream 259 k
publicsuffix-list noarch 20180723-1.el8 local 79 k
sisu-inject noarch 1:0.3.3-6.module+el8+2452+b359bfcd local-AppStream 339 k
sisu-plexus noarch 1:0.3.3-6.module+el8+2452+b359bfcd local-AppStream 180 k
slf4j noarch 1.7.25-4.module+el8+2452+b359bfcd local-AppStream 77 k
ttmkfdir x86_64 3.0.9-54.el8 local-AppStream 62 k
tzdata-java noarch 2019c-1.el8 local-AppStream 189 k
xorg-x11-font-utils x86_64 1:7.5-40.el8 local-AppStream 103 k
xorg-x11-fonts-Type1 noarch 7.5-19.el8 local-AppStream 522 k
Installing weak dependencies:
gtk2 x86_64 2.24.32-4.el8 local-AppStream 3.4 M
Enabling module streams:
javapackages-runtime 201801
maven 3.5
scala 2.10
Transaction Summary
============================================================================
Install 97 Packages
Total size: 65 M
Installed size: 206 M
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Running scriptlet: copy-jdk-configs-3.7-1.el8.noarch 1/1
Running scriptlet: java-1.8.0-openjdk-headless-1:1.8.0.242.b08-4.el8.x86_64 1/1
Preparing : 1/1
Installing : javapackages-filesystem-5.3.0-1.module+el8+2447+6f56d9a6.noarch 1/97
Installing : libjpeg-turbo-1.5.3-10.el8.x86_64 2/97
Installing : gdk-pixbuf2-2.36.12-5.el8.x86_64 3/97
Running scriptlet: gdk-pixbuf2-2.36.12-5.el8.x86_64 3/97
Installing : fontpackages-filesystem-1.44-22.el8.noarch 4/97
Installing : dejavu-fonts-common-2.35-6.el8.noarch 5/97
Installing : dejavu-sans-fonts-2.35-6.el8.noarch 6/97
Installing : fontconfig-2.13.1-3.el8.x86_64 7/97
Running scriptlet: fontconfig-2.13.1-3.el8.x86_64 7/97
Installing : gtk-update-icon-cache-3.22.30-5.el8.x86_64 8/97
Installing : jasper-libs-2.0.14-4.el8.x86_64 9/97
Installing : tzdata-java-2019c-1.el8.noarch 10/97
Installing : ttmkfdir-3.0.9-54.el8.x86_64 11/97
Installing : pixman-0.38.4-1.el8.x86_64 12/97
Installing : lua-5.3.4-11.el8.x86_64 13/97
Installing : copy-jdk-configs-3.7-1.el8.noarch 14/97
Installing : libfontenc-1.1.3-8.el8.x86_64 15/97
Installing : xorg-x11-font-utils-1:7.5-40.el8.x86_64 16/97
Installing : xorg-x11-fonts-Type1-7.5-19.el8.noarch 17/97
Running scriptlet: xorg-x11-fonts-Type1-7.5-19.el8.noarch 17/97
Installing : libdatrie-0.2.9-7.el8.x86_64 18/97
Running scriptlet: libdatrie-0.2.9-7.el8.x86_64 18/97
Installing : libthai-0.1.27-2.el8.x86_64 19/97
Running scriptlet: libthai-0.1.27-2.el8.x86_64 19/97
Installing : libXau-1.0.8-13.el8.x86_64 20/97
Installing : libxcb-1.13.1-1.el8.x86_64 21/97
Installing : libX11-common-1.6.8-3.el8.noarch 22/97
Installing : libX11-1.6.8-3.el8.x86_64 23/97
Installing : libXext-1.3.3-9.el8.x86_64 24/97
Installing : libXrender-0.9.10-7.el8.x86_64 25/97
Installing : libXi-1.7.9-7.el8.x86_64 26/97
Installing : libXfixes-5.0.3-7.el8.x86_64 27/97
Installing : cairo-1.15.12-3.el8.x86_64 28/97
Installing : libXcomposite-0.4.4-14.el8.x86_64 29/97
Installing : libXcursor-1.1.15-3.el8.x86_64 30/97
Installing : libXdamage-1.1.4-14.el8.x86_64 31/97
Installing : libXtst-1.2.3-7.el8.x86_64 32/97
Installing : libXft-2.3.2-10.el8.x86_64 33/97
Installing : libXrandr-1.5.1-7.el8.x86_64 34/97
Installing : libXinerama-1.1.4-1.el8.x86_64 35/97
Installing : jbigkit-libs-2.1-14.el8.x86_64 36/97
Running scriptlet: jbigkit-libs-2.1-14.el8.x86_64 36/97
Installing : libtiff-4.0.9-17.el8.x86_64 37/97
Installing : gdk-pixbuf2-modules-2.36.12-5.el8.x86_64 38/97
Installing : hicolor-icon-theme-0.17-2.el8.noarch 39/97
Installing : graphite2-1.3.10-10.el8.x86_64 40/97
Installing : harfbuzz-1.7.5-3.el8.x86_64 41/97
Running scriptlet: harfbuzz-1.7.5-3.el8.x86_64 41/97
Installing : giflib-5.1.4-3.el8.x86_64 42/97
Installing : fribidi-1.0.4-8.el8.x86_64 43/97
Installing : pango-1.42.4-6.el8.x86_64 44/97
Running scriptlet: pango-1.42.4-6.el8.x86_64 44/97
Installing : atk-2.28.1-1.el8.x86_64 45/97
Installing : alsa-lib-1.2.1.2-3.el8.x86_64 46/97
Running scriptlet: alsa-lib-1.2.1.2-3.el8.x86_64 46/97
Installing : publicsuffix-list-20180723-1.el8.noarch 47/97
Installing : lksctp-tools-1.0.18-3.el8.x86_64 48/97
Running scriptlet: lksctp-tools-1.0.18-3.el8.x86_64 48/97
Installing : avahi-libs-0.7-19.el8.x86_64 49/97
Installing : cups-libs-1:2.2.6-33.el8.x86_64 50/97
Installing : java-1.8.0-openjdk-headless-1:1.8.0.242.b08-4.el8.x86_64 51/97
Running scriptlet: java-1.8.0-openjdk-headless-1:1.8.0.242.b08-4.el8.x86_64 51/97
Installing : maven-resolver-api-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 52/97
Installing : plexus-utils-3.1.0-3.module+el8+2452+b359bfcd.noarch 53/97
Installing : maven-wagon-provider-api-3.1.0-1.module+el8+2452+b359bfcd.noarch 54/97
Installing : maven-resolver-spi-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 55/97
Installing : maven-resolver-util-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 56/97
Installing : atinject-1-28.20100611svn86.module+el8+2452+b359bfcd.noarch 57/97
Installing : httpcomponents-core-4.4.10-3.module+el8+2452+b359bfcd.noarch 58/97
Installing : slf4j-1.7.25-4.module+el8+2452+b359bfcd.noarch 59/97
Installing : apache-commons-io-1:2.6-3.module+el8+2452+b359bfcd.noarch 60/97
Installing : guava20-20.0-8.module+el8+2452+b359bfcd.noarch 61/97
Installing : hawtjni-runtime-1.16-2.module+el8+2452+b359bfcd.noarch 62/97
Installing : plexus-cipher-1.7-14.module+el8+2452+b359bfcd.noarch 63/97
Installing : plexus-classworlds-2.5.2-9.module+el8+2452+b359bfcd.noarch 64/97
Installing : plexus-containers-component-annotations-1.7.1-8.module+el8+2452+b359bfcd.noarch 65/97
Installing : plexus-sec-dispatcher-1.4-26.module+el8+2452+b359bfcd.noarch 66/97
Installing : jansi-native-1.7-7.module+el8+2452+b359bfcd.x86_64 67/97
Installing : maven-shared-utils-3.2.1-0.1.module+el8+2452+b359bfcd.noarch 68/97
Installing : jcl-over-slf4j-1.7.25-4.module+el8+2452+b359bfcd.noarch 69/97
Installing : maven-resolver-impl-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 70/97
Installing : aopalliance-1.0-17.module+el8+2452+b359bfcd.noarch 71/97
Installing : google-guice-4.1-11.module+el8+2452+b359bfcd.noarch 72/97
Installing : apache-commons-cli-1.4-4.module+el8+2452+b359bfcd.noarch 73/97
Installing : apache-commons-codec-1.11-3.module+el8+2452+b359bfcd.noarch 74/97
Installing : apache-commons-lang3-3.7-3.module+el8+2452+b359bfcd.noarch 75/97
Installing : apache-commons-logging-1.2-13.module+el8+2452+b359bfcd.noarch 76/97
Installing : httpcomponents-client-4.5.5-4.module+el8+2452+b359bfcd.noarch 77/97
Installing : geronimo-annotation-1.0-23.module+el8+2452+b359bfcd.noarch 78/97
Installing : plexus-interpolation-1.22-9.module+el8+2452+b359bfcd.noarch 79/97
Installing : jansi-1.17.1-1.module+el8+2477+516cbbff.noarch 80/97
Installing : maven-resolver-connector-basic-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 81/97
Installing : maven-resolver-transport-wagon-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 82/97
Installing : maven-wagon-file-3.1.0-1.module+el8+2452+b359bfcd.noarch 83/97
Installing : glassfish-el-api-3.0.1-0.7.b08.module+el8+2452+b359bfcd.noarch 84/97
Installing : javapackages-tools-5.3.0-1.module+el8+2447+6f56d9a6.noarch 85/97
Installing : jboss-interceptors-1.2-api-1.0.0-8.module+el8+2452+b359bfcd.noarch 86/97
Installing : cdi-api-1.2-8.module+el8+2452+b359bfcd.noarch 87/97
Installing : sisu-inject-1:0.3.3-6.module+el8+2452+b359bfcd.noarch 88/97
Installing : sisu-plexus-1:0.3.3-6.module+el8+2452+b359bfcd.noarch 89/97
Installing : maven-lib-1:3.5.4-5.module+el8+2452+b359bfcd.noarch 90/97
Installing : jsoup-1.11.3-3.module+el8+2452+b359bfcd.noarch 91/97
Installing : maven-wagon-http-shared-3.1.0-1.module+el8+2452+b359bfcd.noarch 92/97
Installing : maven-wagon-http-3.1.0-1.module+el8+2452+b359bfcd.noarch 93/97
Installing : gtk2-2.24.32-4.el8.x86_64 94/97
Running scriptlet: gtk2-2.24.32-4.el8.x86_64 94/97
Installing : java-1.8.0-openjdk-1:1.8.0.242.b08-4.el8.x86_64 95/97
Running scriptlet: java-1.8.0-openjdk-1:1.8.0.242.b08-4.el8.x86_64 95/97
Installing : java-1.8.0-openjdk-devel-1:1.8.0.242.b08-4.el8.x86_64 96/97
Running scriptlet: java-1.8.0-openjdk-devel-1:1.8.0.242.b08-4.el8.x86_64 96/97
Installing : maven-1:3.5.4-5.module+el8+2452+b359bfcd.noarch 97/97
Running scriptlet: maven-1:3.5.4-5.module+el8+2452+b359bfcd.noarch 97/97
Running scriptlet: copy-jdk-configs-3.7-1.el8.noarch 97/97
Running scriptlet: java-1.8.0-openjdk-1:1.8.0.242.b08-4.el8.x86_64 97/97
Running scriptlet: java-1.8.0-openjdk-devel-1:1.8.0.242.b08-4.el8.x86_64 97/97
Running scriptlet: maven-1:3.5.4-5.module+el8+2452+b359bfcd.noarch 97/97
Running scriptlet: gdk-pixbuf2-2.36.12-5.el8.x86_64 97/97
Running scriptlet: fontconfig-2.13.1-3.el8.x86_64 97/97
Running scriptlet: hicolor-icon-theme-0.17-2.el8.noarch 97/97
Verifying : avahi-libs-0.7-19.el8.x86_64 1/97
Verifying : cups-libs-1:2.2.6-33.el8.x86_64 2/97
Verifying : dejavu-fonts-common-2.35-6.el8.noarch 3/97
Verifying : dejavu-sans-fonts-2.35-6.el8.noarch 4/97
Verifying : fontconfig-2.13.1-3.el8.x86_64 5/97
Verifying : fontpackages-filesystem-1.44-22.el8.noarch 6/97
Verifying : gdk-pixbuf2-2.36.12-5.el8.x86_64 7/97
Verifying : lksctp-tools-1.0.18-3.el8.x86_64 8/97
Verifying : publicsuffix-list-20180723-1.el8.noarch 9/97
Verifying : alsa-lib-1.2.1.2-3.el8.x86_64 10/97
Verifying : aopalliance-1.0-17.module+el8+2452+b359bfcd.noarch 11/97
Verifying : apache-commons-cli-1.4-4.module+el8+2452+b359bfcd.noarch 12/97
Verifying : apache-commons-codec-1.11-3.module+el8+2452+b359bfcd.noarch 13/97
Verifying : apache-commons-io-1:2.6-3.module+el8+2452+b359bfcd.noarch 14/97
Verifying : apache-commons-lang3-3.7-3.module+el8+2452+b359bfcd.noarch 15/97
Verifying : apache-commons-logging-1.2-13.module+el8+2452+b359bfcd.noarch 16/97
Verifying : atinject-1-28.20100611svn86.module+el8+2452+b359bfcd.noarch 17/97
Verifying : atk-2.28.1-1.el8.x86_64 18/97
Verifying : cairo-1.15.12-3.el8.x86_64 19/97
Verifying : cdi-api-1.2-8.module+el8+2452+b359bfcd.noarch 20/97
Verifying : copy-jdk-configs-3.7-1.el8.noarch 21/97
Verifying : fribidi-1.0.4-8.el8.x86_64 22/97
Verifying : gdk-pixbuf2-modules-2.36.12-5.el8.x86_64 23/97
Verifying : geronimo-annotation-1.0-23.module+el8+2452+b359bfcd.noarch 24/97
Verifying : giflib-5.1.4-3.el8.x86_64 25/97
Verifying : glassfish-el-api-3.0.1-0.7.b08.module+el8+2452+b359bfcd.noarch 26/97
Verifying : google-guice-4.1-11.module+el8+2452+b359bfcd.noarch 27/97
Verifying : graphite2-1.3.10-10.el8.x86_64 28/97
Verifying : gtk-update-icon-cache-3.22.30-5.el8.x86_64 29/97
Verifying : gtk2-2.24.32-4.el8.x86_64 30/97
Verifying : guava20-20.0-8.module+el8+2452+b359bfcd.noarch 31/97
Verifying : harfbuzz-1.7.5-3.el8.x86_64 32/97
Verifying : hawtjni-runtime-1.16-2.module+el8+2452+b359bfcd.noarch 33/97
Verifying : hicolor-icon-theme-0.17-2.el8.noarch 34/97
Verifying : httpcomponents-client-4.5.5-4.module+el8+2452+b359bfcd.noarch 35/97
Verifying : httpcomponents-core-4.4.10-3.module+el8+2452+b359bfcd.noarch 36/97
Verifying : jansi-1.17.1-1.module+el8+2477+516cbbff.noarch 37/97
Verifying : jansi-native-1.7-7.module+el8+2452+b359bfcd.x86_64 38/97
Verifying : jasper-libs-2.0.14-4.el8.x86_64 39/97
Verifying : java-1.8.0-openjdk-1:1.8.0.242.b08-4.el8.x86_64 40/97
Verifying : java-1.8.0-openjdk-devel-1:1.8.0.242.b08-4.el8.x86_64 41/97
Verifying : java-1.8.0-openjdk-headless-1:1.8.0.242.b08-4.el8.x86_64 42/97
Verifying : javapackages-filesystem-5.3.0-1.module+el8+2447+6f56d9a6.noarch 43/97
Verifying : javapackages-tools-5.3.0-1.module+el8+2447+6f56d9a6.noarch 44/97
Verifying : jbigkit-libs-2.1-14.el8.x86_64 45/97
Verifying : jboss-interceptors-1.2-api-1.0.0-8.module+el8+2452+b359bfcd.noarch 46/97
Verifying : jcl-over-slf4j-1.7.25-4.module+el8+2452+b359bfcd.noarch 47/97
Verifying : jsoup-1.11.3-3.module+el8+2452+b359bfcd.noarch 48/97
Verifying : libX11-1.6.8-3.el8.x86_64 49/97
Verifying : libX11-common-1.6.8-3.el8.noarch 50/97
Verifying : libXau-1.0.8-13.el8.x86_64 51/97
Verifying : libXcomposite-0.4.4-14.el8.x86_64 52/97
Verifying : libXcursor-1.1.15-3.el8.x86_64 53/97
Verifying : libXdamage-1.1.4-14.el8.x86_64 54/97
Verifying : libXext-1.3.3-9.el8.x86_64 55/97
Verifying : libXfixes-5.0.3-7.el8.x86_64 56/97
Verifying : libXft-2.3.2-10.el8.x86_64 57/97
Verifying : libXi-1.7.9-7.el8.x86_64 58/97
Verifying : libXinerama-1.1.4-1.el8.x86_64 59/97
Verifying : libXrandr-1.5.1-7.el8.x86_64 60/97
Verifying : libXrender-0.9.10-7.el8.x86_64 61/97
Verifying : libXtst-1.2.3-7.el8.x86_64 62/97
Verifying : libdatrie-0.2.9-7.el8.x86_64 63/97
Verifying : libfontenc-1.1.3-8.el8.x86_64 64/97
Verifying : libjpeg-turbo-1.5.3-10.el8.x86_64 65/97
Verifying : libthai-0.1.27-2.el8.x86_64 66/97
Verifying : libtiff-4.0.9-17.el8.x86_64 67/97
Verifying : libxcb-1.13.1-1.el8.x86_64 68/97
Verifying : lua-5.3.4-11.el8.x86_64 69/97
Verifying : maven-1:3.5.4-5.module+el8+2452+b359bfcd.noarch 70/97
Verifying : maven-lib-1:3.5.4-5.module+el8+2452+b359bfcd.noarch 71/97
Verifying : maven-resolver-api-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 72/97
Verifying : maven-resolver-connector-basic-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 73/97
Verifying : maven-resolver-impl-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 74/97
Verifying : maven-resolver-spi-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 75/97
Verifying : maven-resolver-transport-wagon-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 76/97
Verifying : maven-resolver-util-1:1.1.1-2.module+el8+2452+b359bfcd.noarch 77/97
Verifying : maven-shared-utils-3.2.1-0.1.module+el8+2452+b359bfcd.noarch 78/97
Verifying : maven-wagon-file-3.1.0-1.module+el8+2452+b359bfcd.noarch 79/97
Verifying : maven-wagon-http-3.1.0-1.module+el8+2452+b359bfcd.noarch 80/97
Verifying : maven-wagon-http-shared-3.1.0-1.module+el8+2452+b359bfcd.noarch 81/97
Verifying : maven-wagon-provider-api-3.1.0-1.module+el8+2452+b359bfcd.noarch 82/97
Verifying : pango-1.42.4-6.el8.x86_64 83/97
Verifying : pixman-0.38.4-1.el8.x86_64 84/97
Verifying : plexus-cipher-1.7-14.module+el8+2452+b359bfcd.noarch 85/97
Verifying : plexus-classworlds-2.5.2-9.module+el8+2452+b359bfcd.noarch 86/97
Verifying : plexus-containers-component-annotations-1.7.1-8.module+el8+2452+b359bfcd.noarch 87/97
Verifying : plexus-interpolation-1.22-9.module+el8+2452+b359bfcd.noarch 88/97
Verifying : plexus-sec-dispatcher-1.4-26.module+el8+2452+b359bfcd.noarch 89/97
Verifying : plexus-utils-3.1.0-3.module+el8+2452+b359bfcd.noarch 90/97
Verifying : sisu-inject-1:0.3.3-6.module+el8+2452+b359bfcd.noarch 91/97
Verifying : sisu-plexus-1:0.3.3-6.module+el8+2452+b359bfcd.noarch 92/97
Verifying : slf4j-1.7.25-4.module+el8+2452+b359bfcd.noarch 93/97
Verifying : ttmkfdir-3.0.9-54.el8.x86_64 94/97
Verifying : tzdata-java-2019c-1.el8.noarch 95/97
Verifying : xorg-x11-font-utils-1:7.5-40.el8.x86_64 96/97
Verifying : xorg-x11-fonts-Type1-7.5-19.el8.noarch 97/97
Installed products updated.
Installed:
alsa-lib-1.2.1.2-3.el8.x86_64 aopalliance-1.0-17.module+el8+2452+b359bfcd.noarch
apache-commons-cli-1.4-4.module+el8+2452+b359bfcd.noarch apache-commons-codec-1.11-3.module+el8+2452+b359bfcd.noarch
apache-commons-io-1:2.6-3.module+el8+2452+b359bfcd.noarch apache-commons-lang3-3.7-3.module+el8+2452+b359bfcd.noarch
apache-commons-logging-1.2-13.module+el8+2452+b359bfcd.noarch atinject-1-28.20100611svn86.module+el8+2452+b359bfcd.noarch
atk-2.28.1-1.el8.x86_64 avahi-libs-0.7-19.el8.x86_64
cairo-1.15.12-3.el8.x86_64 cdi-api-1.2-8.module+el8+2452+b359bfcd.noarch
copy-jdk-configs-3.7-1.el8.noarch cups-libs-1:2.2.6-33.el8.x86_64
dejavu-fonts-common-2.35-6.el8.noarch dejavu-sans-fonts-2.35-6.el8.noarch
fontconfig-2.13.1-3.el8.x86_64 fontpackages-filesystem-1.44-22.el8.noarch
fribidi-1.0.4-8.el8.x86_64 gdk-pixbuf2-2.36.12-5.el8.x86_64
gdk-pixbuf2-modules-2.36.12-5.el8.x86_64 geronimo-annotation-1.0-23.module+el8+2452+b359bfcd.noarch
giflib-5.1.4-3.el8.x86_64 glassfish-el-api-3.0.1-0.7.b08.module+el8+2452+b359bfcd.noarch
google-guice-4.1-11.module+el8+2452+b359bfcd.noarch graphite2-1.3.10-10.el8.x86_64
gtk-update-icon-cache-3.22.30-5.el8.x86_64 gtk2-2.24.32-4.el8.x86_64
guava20-20.0-8.module+el8+2452+b359bfcd.noarch harfbuzz-1.7.5-3.el8.x86_64
hawtjni-runtime-1.16-2.module+el8+2452+b359bfcd.noarch hicolor-icon-theme-0.17-2.el8.noarch
httpcomponents-client-4.5.5-4.module+el8+2452+b359bfcd.noarch httpcomponents-core-4.4.10-3.module+el8+2452+b359bfcd.noarch
jansi-1.17.1-1.module+el8+2477+516cbbff.noarch jansi-native-1.7-7.module+el8+2452+b359bfcd.x86_64
jasper-libs-2.0.14-4.el8.x86_64 java-1.8.0-openjdk-1:1.8.0.242.b08-4.el8.x86_64
java-1.8.0-openjdk-devel-1:1.8.0.242.b08-4.el8.x86_64 java-1.8.0-openjdk-headless-1:1.8.0.242.b08-4.el8.x86_64
javapackages-filesystem-5.3.0-1.module+el8+2447+6f56d9a6.noarch javapackages-tools-5.3.0-1.module+el8+2447+6f56d9a6.noarch
jbigkit-libs-2.1-14.el8.x86_64 jboss-interceptors-1.2-api-1.0.0-8.module+el8+2452+b359bfcd.noarch
jcl-over-slf4j-1.7.25-4.module+el8+2452+b359bfcd.noarch jsoup-1.11.3-3.module+el8+2452+b359bfcd.noarch
libX11-1.6.8-3.el8.x86_64 libX11-common-1.6.8-3.el8.noarch
libXau-1.0.8-13.el8.x86_64 libXcomposite-0.4.4-14.el8.x86_64
libXcursor-1.1.15-3.el8.x86_64 libXdamage-1.1.4-14.el8.x86_64
libXext-1.3.3-9.el8.x86_64 libXfixes-5.0.3-7.el8.x86_64
libXft-2.3.2-10.el8.x86_64 libXi-1.7.9-7.el8.x86_64
libXinerama-1.1.4-1.el8.x86_64 libXrandr-1.5.1-7.el8.x86_64
libXrender-0.9.10-7.el8.x86_64 libXtst-1.2.3-7.el8.x86_64
libdatrie-0.2.9-7.el8.x86_64 libfontenc-1.1.3-8.el8.x86_64
libjpeg-turbo-1.5.3-10.el8.x86_64 libthai-0.1.27-2.el8.x86_64
libtiff-4.0.9-17.el8.x86_64 libxcb-1.13.1-1.el8.x86_64
lksctp-tools-1.0.18-3.el8.x86_64 lua-5.3.4-11.el8.x86_64
maven-1:3.5.4-5.module+el8+2452+b359bfcd.noarch maven-lib-1:3.5.4-5.module+el8+2452+b359bfcd.noarch
maven-resolver-api-1:1.1.1-2.module+el8+2452+b359bfcd.noarch maven-resolver-connector-basic-1:1.1.1-2.module+el8+2452+b359bfcd.noarch
maven-resolver-impl-1:1.1.1-2.module+el8+2452+b359bfcd.noarch maven-resolver-spi-1:1.1.1-2.module+el8+2452+b359bfcd.noarch
maven-resolver-transport-wagon-1:1.1.1-2.module+el8+2452+b359bfcd.noarch maven-resolver-util-1:1.1.1-2.module+el8+2452+b359bfcd.noarch
maven-shared-utils-3.2.1-0.1.module+el8+2452+b359bfcd.noarch maven-wagon-file-3.1.0-1.module+el8+2452+b359bfcd.noarch
maven-wagon-http-3.1.0-1.module+el8+2452+b359bfcd.noarch maven-wagon-http-shared-3.1.0-1.module+el8+2452+b359bfcd.noarch
maven-wagon-provider-api-3.1.0-1.module+el8+2452+b359bfcd.noarch pango-1.42.4-6.el8.x86_64
pixman-0.38.4-1.el8.x86_64 plexus-cipher-1.7-14.module+el8+2452+b359bfcd.noarch
plexus-classworlds-2.5.2-9.module+el8+2452+b359bfcd.noarch plexus-containers-component-annotations-1.7.1-8.module+el8+2452+b359bfcd.noarch
plexus-interpolation-1.22-9.module+el8+2452+b359bfcd.noarch plexus-sec-dispatcher-1.4-26.module+el8+2452+b359bfcd.noarch
plexus-utils-3.1.0-3.module+el8+2452+b359bfcd.noarch publicsuffix-list-20180723-1.el8.noarch
sisu-inject-1:0.3.3-6.module+el8+2452+b359bfcd.noarch sisu-plexus-1:0.3.3-6.module+el8+2452+b359bfcd.noarch
slf4j-1.7.25-4.module+el8+2452+b359bfcd.noarch ttmkfdir-3.0.9-54.el8.x86_64
tzdata-java-2019c-1.el8.noarch xorg-x11-font-utils-1:7.5-40.el8.x86_64
xorg-x11-fonts-Type1-7.5-19.el8.noarch
Complete!
## 查看版本
# mvn --version
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 1.8.0_242, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-4.el8.x86_64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.18.0-193.el8.x86_64", arch: "amd64", family: "unix"
- 编译
csharp
mvn clean compile
## 结果如下
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< com.finance:router-test >-----------------------
[INFO] Building router-test 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom
...
Downloaded from central: https://repo.maven.apache.org/maven2/mysql/mysql-connector-java/8.0.28/mysql-connector-java-8.0.28.jar (2.5 MB at 577 kB/s)
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ router-test ---
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-api/2.0.6/maven-plugin-api-2.0.6.pom
...
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-api/2.0.6/maven-plugin-api-2.0.6.jar (13 kB at 24 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0/plexus-utils-3.0.jar (226 kB at 346 kB/s)
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ router-test ---
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/maven-project/2.0.6/maven-project-2.0.6.pom
...
Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/3.8.2/junit-3.8.2.jar (121 kB at 19 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/com/google/collections/google-collections/1.0/google-collections-1.0.jar (640 kB at 90 kB/s)
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /root/finance-test/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:29 min
[INFO] Finished at: 2026-01-29T14:05:56+08:00
[INFO] ------------------------------------------------------------------------
- 运行
ini
mvn exec:java -Dexec.mainClass="FinanceApp"
## 运行日志
# mvn exec:java -Dexec.mainClass="FinanceApp"
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< com.finance:router-test >-----------------------
[INFO] Building router-test 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- exec-maven-plugin:3.1.0:java (default-cli) @ router-test ---
[FinanceApp.main()] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
[FinanceApp.main()] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
>>> 正在启动金融交易模拟测试...
[SUCCESS] 写入耗时: 47ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 16ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 18ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 15ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 17ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 16ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 17ms | 当前数据库节点: mgr-node1
...
程序运行后,你会看到每秒输出一行,节点应该是 192.168.31.101(你的 Primary)
4 模拟故障演练
故障模拟:杀掉 Primary
假设当前 Primary 是 31.101。
arduino
# 在 31.101 节点执行
systemctl stop mysqld
前端现象
- 第一秒: Java 程序抛出
Communications link failure或The last packet successfully received from the server was...。 - 第二秒: HikariCP 连接池发现连接失效,开始重连。
- 第三秒: 请求经过 Router,Router 已经把 6446 指向了新选出的
1.11。 - 第四秒: 业务恢复,
getTargetServer输出变更为1.11。
less
[SUCCESS] 写入耗时: 13ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 19ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 24ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 15ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 15ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 16ms | 当前数据库节点: mgr-node1
[SUCCESS] 写入耗时: 11ms | 当前数据库节点: mgr-node1
[FinanceApp.main()] WARN com.zaxxer.hikari.pool.ProxyConnection - HikariPool-1 - Connection com.mysql.cj.jdbc.ConnectionImpl@7e924ea0 marked as broken because of SQLSTATE(08S01), ErrorCode(0)
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet successfully received from the server was 2,214 milliseconds ago. The last packet sent successfully to the server was 2,214 milliseconds ago.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1098)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1046)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1371)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1031)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at FinanceApp.main(FinanceApp.java:38)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:279)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
The last packet successfully received from the server was 2,214 milliseconds ago. The last packet sent successfully to the server was 2,214 milliseconds ago.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151)
at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:167)
at com.mysql.cj.protocol.a.NativeProtocol.readMessage(NativeProtocol.java:520)
at com.mysql.cj.protocol.a.NativeProtocol.checkErrorMessage(NativeProtocol.java:700)
at com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol.java:639)
at com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol.java:987)
at com.mysql.cj.NativeSession.execSQL(NativeSession.java:666)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:930)
... 9 more
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.cj.protocol.FullReadInputStream.readFully(FullReadInputStream.java:67)
at com.mysql.cj.protocol.a.SimplePacketReader.readHeaderLocal(SimplePacketReader.java:81)
at com.mysql.cj.protocol.a.SimplePacketReader.readHeader(SimplePacketReader.java:63)
at com.mysql.cj.protocol.a.SimplePacketReader.readHeader(SimplePacketReader.java:45)
at com.mysql.cj.protocol.a.TimeTrackingPacketReader.readHeader(TimeTrackingPacketReader.java:52)
at com.mysql.cj.protocol.a.TimeTrackingPacketReader.readHeader(TimeTrackingPacketReader.java:41)
at com.mysql.cj.protocol.a.MultiPacketReader.readHeader(MultiPacketReader.java:54)
at com.mysql.cj.protocol.a.MultiPacketReader.readHeader(MultiPacketReader.java:44)
at com.mysql.cj.protocol.a.NativeProtocol.readMessage(NativeProtocol.java:514)
... 14 more
[ERROR] 业务瞬间中断: Communications link failure
The last packet successfully received from the server was 2,214 milliseconds ago. The last packet sent successfully to the server was 2,214 milliseconds ago.
[FinanceApp.main()] WARN com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@559ded1c (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
[FinanceApp.main()] WARN com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@4a8ce297 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
[FinanceApp.main()] WARN com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@64cf502f (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
[FinanceApp.main()] WARN com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@3eaf25dc (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
[SUCCESS] 写入耗时: 37ms | 当前数据库节点: mgr-node3
[SUCCESS] 写入耗时: 19ms | 当前数据库节点: mgr-node3
[SUCCESS] 写入耗时: 20ms | 当前数据库节点: mgr-node3
[SUCCESS] 写入耗时: 14ms | 当前数据库节点: mgr-node3
[SUCCESS] 写入耗时: 13ms | 当前数据库节点: mgr-node3
[SUCCESS] 写入耗时: 16ms | 当前数据库节点: mgr-node3
日志确认
- Router 日志 (
/etc/mysqlrouter/finance_instance/log/mysqlrouter.log):
ini
2026-01-29 14:21:35 metadata_cache INFO [7f5a4c3b0700] Metadata for cluster 'finance_cluster' has 3 member(s), single-primary:
2026-01-29 14:21:35 metadata_cache INFO [7f5a4c3b0700] mgr-node1:3306 / 33060 - mode=RW
2026-01-29 14:21:35 metadata_cache INFO [7f5a4c3b0700] mgr-node3:3306 / 33060 - mode=RO
2026-01-29 14:21:35 metadata_cache INFO [7f5a4c3b0700] mgr-node2:3306 / 33060 - mode=RO
2026-01-29 14:22:04 metadata_cache WARNING [7f5a4c3b0700] Failed connecting with Metadata Server mgr-node1:3306: Lost connection to MySQL server at 'reading initial communication packet', system error: 104 (2013)
2026-01-29 14:22:04 metadata_cache WARNING [7f5a4c3b0700] While updating metadata, could not establish a connection to cluster 'finance_cluster' through mgr-node1:3306
2026-01-29 14:22:04 metadata_cache WARNING [7f5a4c3b0700] Member mgr-node1:3306 (8fdf4d79-fb59-11f0-ba9c-bc24116a13f0) defined in metadata not found in actual Group Replication
2026-01-29 14:22:04 metadata_cache INFO [7f5a4c3b0700] Potential changes detected in cluster after metadata refresh (view_id=0)
2026-01-29 14:22:04 metadata_cache INFO [7f5a4c3b0700] Metadata for cluster 'finance_cluster' has 3 member(s), single-primary:
2026-01-29 14:22:04 metadata_cache INFO [7f5a4c3b0700] mgr-node1:3306 / 33060 - mode=n/a
2026-01-29 14:22:04 metadata_cache INFO [7f5a4c3b0700] mgr-node3:3306 / 33060 - mode=RW
2026-01-29 14:22:04 metadata_cache INFO [7f5a4c3b0700] mgr-node2:3306 / 33060 - mode=RO
2026-01-29 14:22:04 routing INFO [7f5a4c3b0700] Disconnecting client 192.168.31.106:33658 from server 192.168.31.101:3306
2026-01-29 14:22:04 routing INFO [7f5a4c3b0700] Disconnecting client 192.168.31.106:33664 from server 192.168.31.101:3306
2026-01-29 14:22:04 routing INFO [7f5a4c3b0700] Disconnecting client 192.168.31.106:33672 from server 192.168.31.101:3306
2026-01-29 14:22:04 routing INFO [7f5a4c3b0700] Disconnecting client 192.168.31.106:33676 from server 192.168.31.101:3306
2026-01-29 14:22:04 routing INFO [7f5a4c3b0700] Disconnecting client 192.168.31.106:33668 from server 192.168.31.101:3306
2026-01-29 14:22:04 routing INFO [7f5a4c3b0700] Routing routing:bootstrap_rw listening on '0.0.0.0:6446, /etc/mysqlrouter/finance_instance/mysql.sock' got request to disconnect 5 invalid connections: metadata change
- MGR 数据库日志:
less
## node2
2026-01-29T06:22:01.411440Z 0 [Warning] [MY-011499] [Repl] Plugin group_replication reported: 'Members removed from the group: mgr-node1:3306'
2026-01-29T06:22:01.411515Z 0 [System] [MY-011500] [Repl] Plugin group_replication reported: 'Primary server with address mgr-node1:3306 left the group. Electing new Primary.'
2026-01-29T06:22:01.411676Z 0 [System] [MY-011507] [Repl] Plugin group_replication reported: 'A new primary with address mgr-node3:3306 was elected. The new primary will execute all previous group transactions before allowing writes.'
2026-01-29T06:22:01.411900Z 0 [System] [MY-011503] [Repl] Plugin group_replication reported: 'Group membership changed to mgr-node3:3306, mgr-node2:3306 on view 17696674232033963:8.'
2026-01-29T06:22:01.412605Z 594 [System] [MY-011565] [Repl] Plugin group_replication reported: 'Setting super_read_only=ON.'
2026-01-29T06:22:01.412672Z 594 [System] [MY-011511] [Repl] Plugin group_replication reported: 'This server is working as secondary member with primary member address mgr-node3:3306.'
## node3
2026-01-29T06:22:01.286858Z 0 [Warning] [MY-011499] [Repl] Plugin group_replication reported: 'Members removed from the group: mgr-node1:3306'
2026-01-29T06:22:01.286979Z 0 [System] [MY-011500] [Repl] Plugin group_replication reported: 'Primary server with address mgr-node1:3306 left the group. Electing new Primary.'
2026-01-29T06:22:01.287223Z 0 [System] [MY-011507] [Repl] Plugin group_replication reported: 'A new primary with address mgr-node3:3306 was elected. The new primary will execute all previous group transactions before allowing writes.'
2026-01-29T06:22:01.287491Z 0 [System] [MY-011503] [Repl] Plugin group_replication reported: 'Group membership changed to mgr-node3:3306, mgr-node2:3306 on view 17696674232033963:8.'
2026-01-29T06:22:01.287892Z 591 [System] [MY-011565] [Repl] Plugin group_replication reported: 'Setting super_read_only=ON.'
2026-01-29T06:22:01.288350Z 577 [System] [MY-013731] [Repl] Plugin group_replication reported: 'The member action "mysql_disable_super_read_only_if_primary" for event "AFTER_PRIMARY_ELECTION" with priority "1" will be run.'
2026-01-29T06:22:01.288396Z 577 [System] [MY-011566] [Repl] Plugin group_replication reported: 'Setting super_read_only=OFF.'
2026-01-29T06:22:01.288573Z 577 [System] [MY-013731] [Repl] Plugin group_replication reported: 'The member action "mysql_start_failover_channels_if_primary" for event "AFTER_PRIMARY_ELECTION" with priority "10" will be run.'
2026-01-29T06:22:01.289295Z 591 [System] [MY-011510] [Repl] Plugin group_replication reported: 'This server is working as primary member.'
- 当前成员
sql
mysql> SELECT MEMBER_ID,MEMBER_HOST,MEMBER_PORT,MEMBER_STATE,MEMBER_ROLE,MEMBER_VERSION FROM performance_schema.replication_group_members;
+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| 6db421a2-fb59-11f0-99ab-bc24110512df | mgr-node3 | 3306 | ONLINE | PRIMARY | 8.0.45 |
| 8b4a22ea-fb59-11f0-b92c-bc2411b87e43 | mgr-node2 | 3306 | ONLINE | SECONDARY | 8.0.45 |
+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
2 rows in set (0.00 sec)
常用维护
有时候需要维护 Primary 机器,需要优雅切换:
sql
-- 在任一节点执行,强制 1.12 成为新主
SELECT group_replication_set_as_primary('指定成员的 UUID');
执行后,你会发现 Router 会立刻自动更新指向,业务连接会自动重连到新主。
监控 Router 状态
因为 Router 是从数据库的"花名册"里读状态的,你直接去数据库里看 Router 登记了什么信息,这是最准的。在任意一台 MGR 节点执行:
sql
-- 1. 查看 Router 实例的活跃状态
SELECT * FROM mysql_innodb_cluster_metadata.routers;
mysql> SELECT * FROM mysql_innodb_cluster_metadata.routers\G;
*************************** 1. row ***************************
router_id: 1
router_name:
product_name: MySQL Router
address: rhel82-node106
version: 8.0.45
last_check_in: 2026-01-29 14:34:30
attributes: {"ROEndpoint": "6447", "RWEndpoint": "6446", "ROXEndpoint": "6449", "RWXEndpoint": "6448", "MetadataUser": "mysql_router1_gbf0w3y", "bootstrapTargetType": "cluster"}
cluster_id: f1ec5e82-fc27-11f0-9ef7-bc24116a13f0
options: NULL
clusterset_id: NULL
1 row in set (0.00 sec)
-- 2. 查看当前 Router 认为的节点角色和健康度(由 Shell 维护)
-- 这个视图会告诉你 Router 应该往哪转发
SELECT * FROM mysql_innodb_cluster_metadata.instances;
mysql> SELECT * FROM mysql_innodb_cluster_metadata.instances;
+-------------+--------------------------------------+----------------+--------------------------------------+----------------+----------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+-------------+
| instance_id | cluster_id | address | mysql_server_uuid | instance_name | addresses | attributes | description |
+-------------+--------------------------------------+----------------+--------------------------------------+----------------+----------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+-------------+
| 1 | f1ec5e82-fc27-11f0-9ef7-bc24116a13f0 | mgr-node3:3306 | 6db421a2-fb59-11f0-99ab-bc24110512df | mgr-node3:3306 | {"mysqlX": "mgr-node3:33060", "grLocal": "192.168.31.103:33061", "mysqlClassic": "mgr-node3:3306"} | {"server_id": 103, "recoveryAccountHost": "%", "recoveryAccountUser": "mysql_innodb_cluster_103"} | NULL |
| 2 | f1ec5e82-fc27-11f0-9ef7-bc24116a13f0 | mgr-node2:3306 | 8b4a22ea-fb59-11f0-b92c-bc2411b87e43 | mgr-node2:3306 | {"mysqlX": "mgr-node2:33060", "grLocal": "192.168.31.102:33061", "mysqlClassic": "mgr-node2:3306"} | {"server_id": 102, "recoveryAccountHost": "%", "recoveryAccountUser": "mysql_innodb_cluster_102"} | NULL |
| 3 | f1ec5e82-fc27-11f0-9ef7-bc24116a13f0 | mgr-node1:3306 | 8fdf4d79-fb59-11f0-ba9c-bc24116a13f0 | mgr-node1:3306 | {"mysqlX": "mgr-node1:33060", "grLocal": "192.168.31.101:33061", "mysqlClassic": "mgr-node1:3306"} | {"server_id": 101, "recoveryAccountHost": "%", "recoveryAccountUser": "mysql_innodb_cluster_101"} | NULL |
+-------------+--------------------------------------+----------------+--------------------------------------+----------------+----------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+-------------+
3 rows in set (0.00 sec)
生产环境避坑指南
- 大事务禁忌: MGR 对大事务(超过 100MB)敏感。如果在 6446 端口跑巨大的
UPDATE,可能导致全集群卡顿,甚至 Router 认为集群不可用。 - 防止"僵尸连接": 在 RHEL 8 层面,优化
net.ipv4.tcp_keepalive_time = 60。当网络发生分区时,这能帮 Router 更快地感知到断开。 - Router 自身的高可用: 如果你采用独立部署模式,请在应用端的 JDBC URL 里写上两个 Router 的 IP(如上文 Java 代码所示),这比 VIP 稳定得多。
总结
本文通过在 RHEL 8 环境下部署 MySQL Router 8.0.45 与 MGR (Single-Primary) 集群,深度实战了金融级数据库的高可用架构。以下是全文的核心技术要点总结:
- 架构解耦与透明化 : 通过 MySQL Router 的 Metadata Cache 机制,应用层不再需要维护复杂的 VIP 或硬编码多个数据库 IP。业务只需连接 Router 提供的固定端口(6446/6447),即可实现读写请求的自动路由与拓扑感知。
- 集群纳管与自治 : 实战证明,利用 MySQL Shell 对原生 MGR 进行"收编"(Adopt),是实现 Router 自动感知的先决条件。这一步将散装的数据库实例转变为具备"自我意识"的 InnoDB Cluster 体系,为自动故障转移奠定了元数据基础。
- 全链路高可用验证 : 通过 Java (HikariCP) 模拟高频交易发现,在 Primary 节点宕机瞬间,系统虽会经历极短的重连阵痛(约 2-5 秒),但得益于 Router 对拓扑变化的毫秒级捕获,业务能够自动在 mgr-node3 等新主节点上恢复运行,实现了真正意义上的 RTO 极小化。
- 专家级运维底线: 金融级场景下,不仅要关注"切换成功",更要关注"切换质量"。优化系统内核的 TCP 保活参数、限制大事务以及通过 Router REST API 建立全方位的监控体系,是确保 7x24 小时生产系统稳定运行的最终护城河。
综上所述,MySQL Router 不仅是 MGR 流量的"分流器",更是弥合数据库高可用与业务零感知之间断层的"粘合剂"。