
業務システムを止めないDB構築 - MySQL InnoDB Clusterの実践構築
こんにちは。クレスコ・デジタルテクノローズのM.Cです。
業務システムの安定稼働に欠かせない「高可用性」を実現するために、MySQL InnoDB Clusterを実際に構築し、その手順やポイントをまとめました。
本記事は、MySQLの基本操作に触れたことがある方を対象に、実践的な構築方法を解説します。
■あわせて読まれている資料:
対応事例やネットワークサービス一覧を掲載!
→ネットワークテクノロジーサービス
MySQL InnoDB Clusterとは?
MySQL InnoDB Clusterは、MySQL Server・MySQL Router・MySQL Shellから構成される統合ソリューションです。近年、システム運用では「障害に強く、拡張しやすく、運用しやすい」データベース構成が求められています。
MySQL InnoDB Clusterは、こうしたニーズに応えるために設計されており、高可用性とスケーラビリティを両立できる点が大きな特徴です。
MySQL InnoDB Clusterの構成要素
MySQL Server | Group Replicationを利用し、レプリケーションや |
MySQL Router | MySQL Serverの状態を判断して |
MySQL Shell | AdminAPIを使用し、 |
構築環境
仮想環境 | VirtualBox 7.0.22 |
OS | Rocky Linux release 9.5 |
MySQL Server(mysql-community-server-8.4.5) | DB01、DB02、DB03 |
MySQL Router(mysql-router-community-8.4.5) | DBRT01 |
MySQL Shell(mysql-shell-8.4.5) | DBSH01 |
※共通設定
SELinuxを無効
firewalldを停止
hostsにIPアドレスを記載

構築① MySQL Server
ここからは、実践的な構築方法を紹介します。
まずMySQL Shellを使用してMySQL Server (Group Replication)を構築します。
※今回の構築に必要なMySQLユーザーはすべての権限を付与して作成
・rpl_user(Group Replication構築に使用)
・rt_user(MySQL Router構築に使用)
dba.checkInstanceConfiguration でB01にInnodb Clusterに必要な設定がされているか確認します。
MySQL DB01:33060+ ssl JS > dba.checkInstanceConfiguration('rpl_user@DB01:3306')
Please provide the password for 'rpl_user@DB01:3306': ********
Save password for 'rpl_user@DB01:3306'? [Y]es/[N]o/Ne[v]er (default No): y
Validating MySQL instance at DB01:3306 for use in an InnoDB Cluster...
This instance reports its own address as DB01:3306
Clients and other cluster members will communicate with it through this address by default. If this is not correct, the report_host MySQL system variable should be changed.
Checking whether existing tables comply with Group Replication requirements...
No incompatible tables detected
Checking instance configuration...
NOTE: Some configuration options need to be fixed:
+--------------------------+---------------+----------------+--------------------------------------------------+
| Variable | Current Value | Required Value | Note |
+--------------------------+---------------+----------------+--------------------------------------------------+
| enforce_gtid_consistency | OFF | ON | Update read-only variable and restart the server |
| gtid_mode | OFF | ON | Update read-only variable and restart the server |
| server_id | 1 | <unique ID> | Update read-only variable and restart the server |
+--------------------------+---------------+----------------+--------------------------------------------------+
Some variables need to be changed, but cannot be done dynamically on the server.
NOTE: Please use the dba.configureInstance() command to repair these issues.
{
"config_errors": [
{
"action": "server_update+restart",
"current": "OFF",
"option": "enforce_gtid_consistency",
"required": "ON"
},
{
"action": "server_update+restart",
"current": "OFF",
"option": "gtid_mode",
"required": "ON"
},
{
"action": "server_update+restart",
"current": "1",
"option": "server_id",
"required": "<unique ID>"
}
],
"status": "error"
}必要な設定が足りないためstatusがerrorになります。
dba.configureInstanceで必要な設定を適用します。
MySQL DB01:33060+ ssl JS > dba.configureInstance('rpl_user@DB01:3306')
Configuring MySQL instance at DB01:3306 for use in an InnoDB Cluster...
This instance reports its own address as DB01:3306
Clients and other cluster members will communicate with it through this address by default. If this is not correct, the report_host MySQL system variable should be changed.
applierWorkerThreads will be set to the default value of 4.
NOTE: Some configuration options need to be fixed:
+--------------------------+---------------+----------------+--------------------------------------------------+
| Variable | Current Value | Required Value | Note |
+--------------------------+---------------+----------------+--------------------------------------------------+
| enforce_gtid_consistency | OFF | ON | Update read-only variable and restart the server |
| gtid_mode | OFF | ON | Update read-only variable and restart the server |
| server_id | 1 | <unique ID> | Update read-only variable and restart the server |
+--------------------------+---------------+----------------+--------------------------------------------------+
Some variables need to be changed, but cannot be done dynamically on the server.
Do you want to perform the required configuration changes? [y/n]: y
Do you want to restart the instance after configuring it? [y/n]: y
Configuring instance...
The instance 'DB01:3306' was configured to be used in an InnoDB Cluster.
Restarting MySQL...
NOTE: MySQL server at DB01:3306 was restarted.設定変更とサービス再起動の確認が入るためYesを選択すると設定が完了し、再起動されます。
設定を再度確認します。
MySQL DB01:33060+ ssl JS > dba.checkInstanceConfiguration('rpl_user@DB01:3306')
Validating MySQL instance at DB01:3306 for use in an InnoDB Cluster...
This instance reports its own address as DB01:3306
Clients and other cluster members will communicate with it through this address by default. If this is not correct, the report_host MySQL system variable should be changed.
Checking whether existing tables comply with Group Replication requirements...
No incompatible tables detected
Checking instance configuration...
Instance configuration is compatible with InnoDB cluster
The instance 'DB01:3306' is valid for InnoDB Cluster usage.
{
"status": "ok"
}設定を適用したためstatusがokになります。
次にdba.createClusterでテスト用クラスタを作成します。
MySQL DB01:33060+ ssl JS > var cluster = dba.createCluster('testCluster')
A new InnoDB Cluster will be created on instance 'DB01:3306'.
Validating instance configuration at DB01:3306...
This instance reports its own address as DB01:3306
Instance configuration is suitable.
NOTE: Group Replication will communicate with other members using 'DB01:3306'. Use the localAddress option to override.
* Checking connectivity and SSL configuration...
Creating InnoDB Cluster 'testCluster' on 'DB01:3306'...
Adding Seed Instance...
Cluster successfully created. Use Cluster.addInstance() to add MySQL instances.
At least 3 instances are needed for the cluster to be able to withstand up to
one server failure.テスト用のクラスタが作成されます。
クラスタには最低3つのインスタンスが必要になります。
クラスタの状態確認をします。
MySQL DB01:33060+ ssl JS > cluster.status()
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "DB01:3306",
"ssl": "REQUIRED",
"status": "OK_NO_TOLERANCE",
"statusText": "Cluster is NOT tolerant to any failures.",
"topology": {
"DB01:3306": {
"address": "DB01:3306",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "DB01:3306"
}DB01がmemberRole:PRIMARY、status:ONLINEで追加されていることが確認できます。
DB02/03にも必要な設定を適用します。
MySQL DB01:33060+ ssl JS > dba.configureInstance('rpl_user@DB02:3306')
MySQL DB01:33060+ ssl JS > dba.configureInstance('rpl_user@DB03:3306')
MySQL DB01:33060+ ssl JS > dba.checkInstanceConfiguration('rpl_user@DB02:3306')
MySQL DB01:33060+ ssl JS > dba.checkInstanceConfiguration('rpl_user@DB03:3306')DB01同様にstatusがokになります。
設定が完了したためcluster.addInstance でDB02/03をテスト用クラスタに追加します。
MySQL DB01:33060+ ssl JS > cluster.addInstance('rpl_user@DB02:3306')
NOTE: The target instance 'DB02:3306' has not been pre-provisioned (GTID set is empty). The Shell is unable to decide whether incremental state recovery can correctly provision it.
The safest and most convenient way to provision a new instance is through automatic clone provisioning, which will completely overwrite the state of 'DB02:3306' with a physical snapshot from an existing cluster member. To use this method by default, set the 'recoveryMethod' option to 'clone'.
The incremental state recovery may be safely used if you are sure all updates ever executed in the cluster were done with GTIDs enabled, there are no purged transactions and the new instance contains the same GTID set as the cluster or a subset of it. To use this method by default, set the 'recoveryMethod' option to 'incremental'.
Please select a recovery method [C]lone/[I]ncremental recovery/[A]bort (default Clone): c
Validating instance configuration at DB02:3306...
This instance reports its own address as DB02:3306
Instance configuration is suitable.
NOTE: Group Replication will communicate with other members using 'DB02:3306'. Use the localAddress option to override.
* Checking connectivity and SSL configuration...
A new instance will be added to the InnoDB Cluster. Depending on the amount of
data on the cluster this might take from a few seconds to several hours.
Adding instance to the cluster...
Monitoring recovery process of the new cluster member. Press ^C to stop monitoring and let it continue in background.
Clone based state recovery is now in progress.
NOTE: A server restart is expected to happen as part of the clone process. If the
server does not support the RESTART command or does not come back after a
while, you may need to manually start it back.
* Waiting for clone to finish...
NOTE: DB02:3306 is being cloned from db01:3306
** Stage DROP DATA: Completed
** Clone Transfer
FILE COPY ############################################################ 100% Completed
PAGE COPY ############################################################ 100% Completed
REDO COPY ############################################################ 100% Completed
NOTE: DB02:3306 is shutting down...
* Waiting for server restart... ready
* DB02:3306 has restarted, waiting for clone to finish...
** Stage RESTART: Completed
* Clone process has finished: 73.65 MB transferred in about 1 second (~73.65 MB/s)
State recovery already finished for 'DB02:3306'
The instance 'DB02:3306' was successfully added to the cluster.
MySQL DB01:33060+ ssl JS >
MySQL DB01:33060+ ssl JS > cluster.addInstance('rpl_user@DB03:3306')
NOTE: The target instance 'DB03:3306' has not been pre-provisioned (GTID set is empty). The Shell is unable to decide whether incremental state recovery can correctly provision it.
The safest and most convenient way to provision a new instance is through automatic clone provisioning, which will completely overwrite the state of 'DB03:3306' with a physical snapshot from an existing cluster member. To use this method by default, set the 'recoveryMethod' option to 'clone'.
The incremental state recovery may be safely used if you are sure all updates ever executed in the cluster were done with GTIDs enabled, there are no purged transactions and the new instance contains the same GTID set as the cluster or a subset of it. To use this method by default, set the 'recoveryMethod' option to 'incremental'.
Please select a recovery method [C]lone/[I]ncremental recovery/[A]bort (default Clone): c
Validating instance configuration at DB03:3306...
This instance reports its own address as DB03:3306
Instance configuration is suitable.
NOTE: Group Replication will communicate with other members using 'DB03:3306'. Use the localAddress option to override.
* Checking connectivity and SSL configuration...
A new instance will be added to the InnoDB Cluster. Depending on the amount of
data on the cluster this might take from a few seconds to several hours.
Adding instance to the cluster...
Monitoring recovery process of the new cluster member. Press ^C to stop monitoring and let it continue in background.
Clone based state recovery is now in progress.
NOTE: A server restart is expected to happen as part of the clone process. If the
server does not support the RESTART command or does not come back after a
while, you may need to manually start it back.
* Waiting for clone to finish...
NOTE: DB03:3306 is being cloned from db02:3306
** Stage DROP DATA: Completed
** Clone Transfer
FILE COPY ############################################################ 100% Completed
PAGE COPY ############################################################ 100% Completed
REDO COPY ############################################################ 100% Completed
NOTE: DB03:3306 is shutting down...
* Waiting for server restart... ready
* DB03:3306 has restarted, waiting for clone to finish...
** Stage RESTART: Completed
* Clone process has finished: 73.65 MB transferred in about 1 second (~73.65 MB/s)
State recovery already finished for 'DB03:3306'
The instance 'DB03:3306' was successfully added to the cluster.
DB02/03がテスト用クラスタに追加されます。
インタスタンスが追加されたためクラスタの状態確認をします。
MySQL DB01:33060+ ssl JS > cluster.status()
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "DB01:3306",
"ssl": "REQUIRED",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"DB01:3306": {
"address": "DB01:3306",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
},
"DB02:3306": {
"address": "DB02:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
},
"DB03:3306": {
"address": "DB03:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "DB01:3306"
}DB02/03がmemberRole:SECONDARY、status:ONLINEで追加ていることが確認できます。
これでMySQL Server (Group Replication)の構築が完了しました。
構築② MySQL Router
MySQL Server(Group Replication)の構築ができたらMySQL Routerの構築を行います。
Innodb Clusterにmysqlrouterでブートストラップします。
[root@DBRT01 ~]# mysqlrouter --bootstrap rt_user@DB01:3306 --user=mysqlrouter --account=rt_user
Please enter MySQL password for rt_user:
# Bootstrapping system MySQL Router 8.4.5 (MySQL Community - GPL) instance...
Please enter MySQL password for rt_user:
- 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/mysqlrouter.conf
Existing configuration backed up to '/etc/mysqlrouter/mysqlrouter.conf.bak'
# MySQL Router configured for the InnoDB Cluster 'testCluster'
After this MySQL Router has been started with the generated configuration
$ /etc/init.d/mysqlrouter restart
or
$ systemctl start mysqlrouter
or
$ mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf
InnoDB Cluster 'testCluster' can be reached by connecting to:
## MySQL Classic protocol
- Read/Write Connections: localhost:6446
- Read/Only Connections: localhost:6447
- Read/Write Split Connections: localhost:6450
## MySQL X protocol
- Read/Write Connections: localhost:6448
- Read/Only Connections: localhost:6449MySQL Routerが設定されます。
読み書きは6446ポートで読み取り専用は6447です。
ルータのステータスを確認します。
MySQL DB01:33060+ ssl JS > cluster.listRouters()
{
"clusterName": "testCluster",
"routers": {
"DBRT01::system": {
"hostname": "DBRT01",
"lastCheckIn": "2025-06-21 20:24:34",
"roPort": "6447",
"roXPort": "6449",
"rwPort": "6446",
"rwSplitPort": "6450",
"rwXPort": "6448",
"version": "8.4.5"
}
}
}lastCheckInが最新の日時になっていれることが確認できます。
これでMySLQL Routerの構築も完了しました。
動作確認
レプリケーションとフェールオーバーについて動作を確認します。
・レプリケーション
まずDB01のデータベース一覧を確認します。
MySQL DB01:33060+ ssl SQL > SHOW DATABASES;
+-------------------------------+
| Database |
+-------------------------------+
| information_schema |
| mysql |
| mysql_innodb_cluster_metadata |
| performance_schema |
| sys |
+-------------------------------+
5 rows in set (0.0016 sec)DB01にDB作成、テーブル作成、データ挿入します。
MySQL DB01:33060+ ssl SQL > CREATE DATABASE test;
Query OK, 1 row affected (0.0620 sec)
MySQL DB01:33060+ ssl SQL > USE test;
Default schema set to `test`.
Fetching global names, object names from `test` for auto-completion... Press ^C to stop.
MySQL DB01:33060+ ssl test SQL > CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL);
Query OK, 0 rows affected (0.1588 sec)
MySQL DB01:33060+ ssl test SQL > INSERT INTO t1 VALUES (1, 'Luis');
Query OK, 1 row affected (0.0291 sec)
MySQL DB01:33060+ ssl test SQL > SELECT * FROM t1;
+----+------+
| c1 | c2 |
+----+------+
| 1 | Luis |
+----+------+
1 row in set (0.0011 sec)
DB02のデータベース一覧を確認します。
MySQL DB02:3306 ssl SQL > SHOW DATABASES;
+-------------------------------+
| Database |
+-------------------------------+
| information_schema |
| mysql |
| mysql_innodb_cluster_metadata |
| performance_schema |
| sys |
| test |
+-------------------------------+
6 rows in set (0.0013 sec)
MySQL DB02:33060+ ssl SQL > USE test;
MySQL DB02:33060+ ssl test SQL > SELECT * FROM t1;
+----+------+
| c1 | c2 |
+----+------+
| 1 | Luis |
+----+------+
1 row in set (0.0036 sec)
MySQL DB02:33060+ ssl test SQL >DB02にも同じデータがレプリケーションされていることが確認できました。
・フェールオーバー + レプリケーション
まずDB01のGroup Replicationを停止します。
MySQL DB01:3306 ssl SQL > STOP GROUP_REPLICATION;
Query OK, 0 rows affected (3.2004 sec)クラスターの状態を確認します。
MySQL DB02:33060+ ssl JS > cluster = dba.getCluster()
<Cluster:testCluster>
MySQL DB02:33060+ ssl JS > cluster.status()
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "DB02:3306",
"ssl": "REQUIRED",
"status": "OK_NO_TOLERANCE_PARTIAL",
"statusText": "Cluster is NOT tolerant to any failures. 1 member is not active.",
"topology": {
"DB01:3306": {
"address": "DB01:3306",
"instanceErrors": [
"NOTE: group_replication is stopped."
],
"memberRole": "SECONDARY",
"memberState": "OFFLINE",
"mode": "n/a",
"readReplicas": {},
"role": "HA",
"status": "(MISSING)",
"version": "8.4.5"
},
"DB02:3306": {
"address": "DB02:3306",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
},
"DB03:3306": {
"address": "DB03:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "DB02:3306"
}DB01がmemberRole:SECONDARY、status:OFFLINE、
DB02のmemberRole:PRIMARY、status:ONLINEになっていることが確認できます。
DB02にDB作成、テーブル作成、データ挿入します。
MySQL DB02:33060+ ssl SQL > SHOW DATABASES;
+-------------------------------+
| Database |
+-------------------------------+
| information_schema |
| mysql |
| mysql_innodb_cluster_metadata |
| performance_schema |
| sys |
| test |
+-------------------------------+
6 rows in set (0.0020 sec)
MySQL DB02:33060+ ssl SQL > CREATE DATABASE test_recovery;
Query OK, 1 row affected (0.0375 sec)
MySQL DB02:33060+ ssl SQL > USE test_recovery;
Default schema set to `test_recovery`.
Fetching global names, object names from `test_recovery` for auto-completion... Press ^C to stop.
MySQL DB02:33060+ ssl test_recovery SQL > CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL);
Query OK, 0 rows affected (0.1208 sec)
MySQL DB02:33060+ ssl test_recovery SQL > INSERT INTO t1 VALUES (1, 'Luis');
Query OK, 1 row affected (0.0328 sec)
MySQL DB02:33060+ ssl test_recovery SQL > SELECT * FROM t1;
+----+------+
| c1 | c2 |
+----+------+
| 1 | Luis |
+----+------+
1 row in set (0.0019 sec)
MySQL DB02:33060+ ssl test_recovery SQL > SHOW DATABASES;
+-------------------------------+
| Database |
+-------------------------------+
| information_schema |
| mysql |
| mysql_innodb_cluster_metadata |
| performance_schema |
| sys |
| test |
| test_recovery |
+-------------------------------+
7 rows in set (0.0014 sec)
DB01のデータベース一覧を確認します。
MySQL DB01:33060+ ssl SQL > SHOW DATABASES;
+-------------------------------+
| Database |
+-------------------------------+
| information_schema |
| mysql |
| mysql_innodb_cluster_metadata |
| performance_schema |
| sys |
| test |
+-------------------------------+
6 rows in set (0.0015 sec)Group Replicationに参加していないためtest_recoveryが存在しません。
DB01でGroup Replicationに参加します。
MySQL DB01:33060+ ssl SQL > START GROUP_REPLICATION USER='rpl_user', PASSWORD='【パスワード】';
Query OK, 0 rows affected (6.1989 sec)
MySQL DB01:33060+ ssl SQL > SHOW DATABASES;
+-------------------------------+
| Database |
+-------------------------------+
| information_schema |
| mysql |
| mysql_innodb_cluster_metadata |
| performance_schema |
| sys |
| test |
| test_recovery |
+-------------------------------+
7 rows in set (0.0016 sec)
MySQL DB01:33060+ ssl SQL > USE test_recovery;
Default schema set to `test_recovery`.
Fetching global names, object names from `test_recovery` for auto-completion... Press ^C to stop.
MySQL DB01:33060+ ssl test_recovery SQL > SELECT * FROM t1;
+----+------+
| c1 | c2 |
+----+------+
| 1 | Luis |
+----+------+
1 row in set (0.0013 sec)Group Replicationに参加したためtest_recoveryがレプリケーションされていることが確認できました。
これで障害時に自動でフェイルオーバーを行う仕組みの構築が完了となります。
活用例
続いて、MySQL InnoDB Clusterの活用例として、オープンソースの統合監視ソフトウェアのZabbixを取り上げます。Zabbixは、24時間365日システムを監視するため、高可用性が求められるソフトウェアです。
MySQL InnoDB Clusterが自動フェイルオーバーを提供しすることにより、Zabbixは障害時に監視を継続することが可能となります。
そのため、高可用性とスケーラビリティを備えたInnoDB Clusterは、Zabbixのデータベース基盤として非常に相性が良いといえます。
データベースの接続でMySQL Routerを指定することで設定できます。

まとめ
MySQL InnoDB Clusterは、MySQL環境に高可用性をもたらす機能です。
構成の理解から実際の構築、動作確認までを紹介しました。
最後まで読んでいただきありがとうございました。
■サービス資料一覧はこちら↓
引用元
https://dev.mysql.com/doc/refman/8.4/en/






