概要
前回 MySQL8.4.5 で簡単なレプリケーション構成を組んでみました
今回は少し複雑にして Group Replication を使った InnoDB Cluster を構築してみます
なお検証なので docker compose で一発で InnoDB Cluster が構築できるようしています
環境
- macOS 15.5
- docker 28.2.2
- MySQL 8.4.5
compose.yaml
まずは3台の MySQL を Group Replication に必要なオプションを付与して起動します
InnoDB Cluster を構築するには mysqlshell コンテナがクラスタを構築するための Python スクリプトを実行することで構築されます
MySQL の起動オプションのみで InnoDB Cluster を構築できるわけではないので注意しましょう
services:
mysql1:
image: mysql:8.4.5
environment:
- MYSQL_ROOT_PASSWORD=rootpass
ports:
- "33061:3306"
command: >
--mysql-native-password=ON
--server-id=1
--gtid-mode=ON
--enforce-gtid-consistency=ON
--binlog-format=ROW
--log-bin=mysql-bin
--relay-log=relay-bin
--log-replica-updates=ON
--read-only=OFF
volumes:
- mysql1_data:/var/lib/mysql
restart: always
networks:
- mysqlnet
mysql2:
image: mysql:8.4.5
environment:
- MYSQL_ROOT_PASSWORD=rootpass
ports:
- "33062:3306"
command: >
--mysql-native-password=ON
--server-id=2
--gtid-mode=ON
--enforce-gtid-consistency=ON
--binlog-format=ROW
--log-bin=mysql-bin
--relay-log=relay-bin
--log-replica-updates=ON
--read-only=OFF
volumes:
- mysql2_data:/var/lib/mysql
restart: always
networks:
- mysqlnet
mysql3:
image: mysql:8.4.5
environment:
- MYSQL_ROOT_PASSWORD=rootpass
ports:
- "33063:3306"
command: >
--mysql-native-password=ON
--server-id=3
--gtid-mode=ON
--enforce-gtid-consistency=ON
--binlog-format=ROW
--log-bin=mysql-bin
--relay-log=relay-bin
--log-replica-updates=ON
--read-only=OFF
volumes:
- mysql3_data:/var/lib/mysql
restart: always
networks:
- mysqlnet
mysqlshell:
image: mysql:8.4.5
depends_on:
- mysql1
- mysql2
- mysql3
networks:
- mysqlnet
volumes:
- ./scripts:/scripts
command: >
bash -c "
echo 'Waiting for MySQL to be ready...' &&
sleep 15 &&
mysqlsh --host=mysql1 --port=3306 --user=root --password=rootpass --py < /scripts/setup_cluster.py
"
networks:
mysqlnet:
volumes:
mysql1_data:
mysql2_data:
mysql3_data:
./scripts/setup_cluster.py
mysqlsh という機能を使って Python スクリプトを実行します
Python の他に JavaScript でも InnoDB Cluster を操作できます
import time
def wait_and_configure(uri):
for i in range(10):
try:
dba.configure_instance(
uri, {"clusterAdmin": "admin", "clusterAdminPassword": "adminpass"}
)
return
except Exception as e:
print(f"Retry configuring {uri} in 5 sec: {e}")
time.sleep(5)
raise RuntimeError(f"Failed to configure instance: {uri}")
wait_and_configure("root:rootpass@mysql1:3306")
wait_and_configure("root:rootpass@mysql2:3306")
wait_and_configure("root:rootpass@mysql3:3306")
cluster = dba.create_cluster("testCluster")
cluster.add_instance("root:rootpass@mysql2:3306", {"recoveryMethod": "clone"})
cluster.add_instance("root:rootpass@mysql3:3306", {"recoveryMethod": "clone"})
print("Cluster status:")
print(cluster.status())
流れとしては
- 各ノードにクラスタ構築用のユーザを設定 (configure_instance)
- 各ノードの追加 (add_instance)
- クラスタの状態を確認 (status)
という感じになっています
今回は一発で構築するためスクリプトにしましたが各 MySQL を起動したあとに手動で mysqlsh を実行し InnoDB Cluster を構築しても OK です
動作確認
でまずは各種コンテンを起動します
今回は上記一発で InnoDB Cluster が構築できるのであとは構築できたかを mysqlsh を使って確認します
でますは mysqlsh を起動しましょう
root ユーザのパスワードが必要になります
そして Python を使ってクラスタの状況を確認します
dba.get_cluster().status()
以下のようにクラスタが ONLINE で構築されていれば OK です
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "65d9833167a3:3306",
"ssl": "REQUIRED",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"65d9833167a3:3306": {
"address": "65d9833167a3:3306",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
},
"6892d7a7d916:3306": {
"address": "6892d7a7d916:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
},
"bcbe386a9df7:3306": {
"address": "bcbe386a9df7:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "65d9833167a3:3306"
}
どのノードがどのホスト名なのかわかない場合は add_instance 時に label というオプションが指定できるのでそれを使ってホスト名などを指定するといいかなと思います
FailOver の確認
PRIMARY なノードを停止して他のノードが PRIMARY になることを確認しましょう
しばらくしたら再度起動します
これで再度クラスタの状態を確認すると PRIMARY が変わっていることが確認できると思います
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "bcbe386a9df7:3306",
"ssl": "REQUIRED",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"65d9833167a3:3306": {
"address": "65d9833167a3:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
},
"6892d7a7d916:3306": {
"address": "6892d7a7d916:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
},
"bcbe386a9df7:3306": {
"address": "bcbe386a9df7:3306",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.4.5"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "bcbe386a9df7:3306"
}
mysql クライアントを使うときには
基本は普通に使えば OK ですが必ず PRIMARY に接続するようにしましょう
InnoDB Cluster の場合マルチマスター構成なのでどのノードもマスタなので書き込みが出来そうなのですが実際はできずにエラーになります
mysql> create database test;
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
なので Failover 時にはアプリ側で書き込み先を変更しなければいけないのですがそれを自動で行う MySQL Router という機能があるので次回はそれを組み合わせてみます
最後に
MySQL8.4.5 で InnoDB Cluster を構築してみました
構築自体は非常に簡単で MySQL を3台用意して mysqlsh でクラスタを構築するための API をコールするだけでした
これで MySQL の冗長構成 + 自動 FailOver な環境は構築できました
次回は MySQL Router を組み合わせてみます
参考サイト