これは、なにをしたくて書いたもの?
MySQLのInnoDB Clusterを試してみようと思ったのですが、その前にMySQL Shellに触れた方が良さそうな気がしまして。
InnoDB Clusterを組む時に、Group ReplicationをMySQL Shellで組む手順になっているみたいなんですよね。
MySQL :: MySQL 8.0 Reference Manual :: 21.1 Introducing InnoDB Cluster
というか、Group ReplicationにMySQL Routerを足したものがInnoDB Clusterでいいのかな…?
以前にMySQL Shellを使わずにGroup Replicationは組んだことがあるのですが、これとMySQL Shellで組んだ時の差がイマイチわかって
いませんが…。
MySQL 8.0でGroup Replicationを構成してみる - CLOVER🍀
最終的にはInnoDB Clusterを組みたいのですが、今回はMySQL ShellでGroup Replicationの部分を組むところをやってみます。
InnoDB Clusterについては、こちら。
MySQL InnoDB Clusterによる高可用性構成(DB Tech Showcase 2017)
Introduction to MySQL InnoDB Cluster
MySQL Shell
MySQL Shellは、MySQL Serverのクライアントです。mysqlコマンドに、そのうち代わるものになるんでしょうか?
APIドキュメントは、こちら。
MySQL Shellは、MySQL 5.7、8.0以降で使うことができます。
mysqlコマンドと同様にインタラクティブにMySQL Serverを操作したり、バッチ的にコードを実行することもできます。操作に使う言語は、
SQL、JavaScript、Pythonです。
また、AdminAPIを使うとInnoDB Clusterを操作することができます。
概要はこれくらいにして、進めてみましょう。
環境
今回は、MySQL Server 8.0.17、MySQL Shell 8.0.17を使います。
$ # mysqld --version /usr/sbin/mysqld Ver 8.0.17 for Linux on x86_64 (MySQL Community Server - GPL) $ mysqlsh -V Logger: Tried to log to an uninitialized logger. mysqlsh Ver 8.0.17 for Linux on x86_64 - for MySQL 8.0.17 (MySQL Community Server (GPL))
MySQL Serverは3つのインスタンスとし、各サーバーのIPアドレスは以下とします。
server idは、IPアドレスの末尾にしました。
MySQL Shellのインストール
MySQL Shellのインストールは、Linux環境であればMySQLの提供するaptやyumのリポジトリを使ってインストールすることができます。
MySQL :: MySQL Shell 8.0 :: 2.2 Installing MySQL Shell on Linux
MySQL :: Download MySQL APT Repository
MySQL :: Download MySQL Yum Repository
今回の環境は、Ubuntu Linuxで行っているのでaptでインストール。
$ sudo apt install mysql-shell
MySQL Serverの設定
MySQL Serverの、Group Replicationに関する設定は以下のようにしました。
## gtid gtid_mode = on enforce_gtid_consistency = on ## binary log log-bin = mysql-bin sync_binlog = 1 binlog_expire_logs_seconds = 864000 binlog_checksum=NONE ## replication server_id = 2 ## group replication report-host = "172.17.0.2"
server idは、他のサーバーでは別の値にします。
また、report-hostは必須ではないのですが、今回名前解決を使わないようにしたのでIPアドレスを直接記載しました。
report-host = "172.17.0.2"
他のサーバーでは、ここもそれぞれのIPアドレスにします。
ところで、MySQL Shellを使ってMySQL Serverのクラスタを組む際のユーザーなのですが、けっこうな強い権限が必要なようです。
The user account used to administer an instance does not have to be the root account, however the user needs to be assigned full read and write privileges on the InnoDB cluster metadata tables in addition to full MySQL administrator privileges (SUPER, GRANT OPTION, CREATE, DROP and so on).
Configuring Users for InnoDB Cluster
今回はもう簡単に、どこからでもアクセスできるrootユーザーを作成することにしました。
CREATE USER root@'%' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON *.* TO root@'%' WITH GRANT OPTION; FLUSH PRIVILEGES; RESET MASTER;
最後にRESET MASTERを入れているのは、ユーザーを作成した際にバイナリログが出力され、クラスタを組む際にこれがジャマになるからです。
MySQL Group Replicationを使う上での注意点 - Qiita
RESET MASTERを入れることで、バイナリログを1度パージしています。
これをやらなかった場合は、クラスタを組む際にClone Pluginで新しいサーバーに対して、既存のサーバーのデータをまるっとコピーすることに
なります。
クラスタ(Group Replication)を組む
それでは、MySQL Shellを使ってクラスタ(Group Replication)を組んでみましょう。
$ mysqlsh Logger: Tried to log to an uninitialized logger. MySQL Shell 8.0.17 Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. 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.
まずは、ひとつのMySQL Serverに接続します。
MySQL JS > \connect root@172.17.0.2 Creating a session to 'root@172.17.0.2' Please provide the password for 'root@172.17.0.2': ******** Fetching schema names for autocompletion... Press ^C to stop. Your MySQL connection id is 9 (X protocol) Server version: 8.0.17 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one.
MySQL Shellでは、「dba」というオブジェクトを使うことでAdminAPIを使うことができます。
「dba.checkInstanceConfiguration」で、現在接続しているインスタンスがInnoDB Clusterに参加できるかどうかを確認し、
MySQL 172.17.0.2:33060+ ssl JS > dba.checkInstanceConfiguration() Validating MySQL instance at 172.17.0.2:3306 for use in an InnoDB cluster... This instance reports its own address as 172.17.0.2:3306 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 '172.17.0.2:3306' is valid for InnoDB cluster usage. { "status": "ok" }
必要であれば「dba.configureInstance()」で設定を修正することができます。
MySQL 172.17.0.2:33060+ ssl JS > dba.configureInstance() Configuring MySQL instance at 172.17.0.2:3306 for use in an InnoDB cluster... This instance reports its own address as 172.17.0.2:3306 The instance '172.17.0.2:3306' is valid for InnoDB cluster usage. The instance '172.17.0.2:3306' is already ready for InnoDB cluster usage.
では、クラスタを作成します。クラスタ名「test_cluster」で、現在接続しているMySQL Serverをメンバーとしてクラスタを作成します。
MySQL 172.17.0.2:33060+ ssl JS > var cluster = dba.createCluster('test_cluster') A new InnoDB cluster will be created on instance '172.17.0.2:3306'. Validating instance at 172.17.0.2:3306... This instance reports its own address as 172.17.0.2:3306 Instance configuration is suitable. Creating InnoDB cluster 'test_cluster' on '172.17.0.2: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つのインスタンスが必要だ」と言っていますね。
では、残りのインスタンスも追加してみましょう。
「dba.checkInstanceConfiguration」も「dba.configureInstance」も、引数に接続先を取ることができます。こちらを使って、追加対象の
インスタンスの設定を確認してみましょう。
MySQL 172.17.0.2:33060+ ssl JS > dba.checkInstanceConfiguration('root@172.17.0.3') Please provide the password for 'root@172.17.0.3': ******** Validating MySQL instance at 172.17.0.3:3306 for use in an InnoDB cluster... This instance reports its own address as 172.17.0.3:3306 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 '172.17.0.3:3306' is valid for InnoDB cluster usage. { "status": "ok" } MySQL 172.17.0.2:33060+ ssl JS > dba.checkInstanceConfiguration('root@172.17.0.4') Please provide the password for 'root@172.17.0.4': ******** Validating MySQL instance at 172.17.0.4:3306 for use in an InnoDB cluster... This instance reports its own address as 172.17.0.4:3306 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 '172.17.0.4:3306' is valid for InnoDB cluster usage. { "status": "ok" }
OKそうなので、クラスタに追加してみます。
MySQL 172.17.0.2:33060+ ssl JS > cluster.addInstance('root@172.17.0.3') Please provide the password for 'root@172.17.0.3': ******** 〜省略〜 Please select a recovery method [C]lone/[I]ncremental recovery/[A]bort (default Clone): I Validating instance at 172.17.0.3:3306... This instance reports its own address as 172.17.0.3:3306 Instance configuration is suitable. 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. Incremental distributed state recovery is now in progress. * Waiting for distributed recovery to finish... NOTE: '172.17.0.3:3306' is being recovered from '172.17.0.2:3306' * Distributed recovery has finished The instance '172.17.0.3' was successfully added to the cluster.
この「〜省略〜」としている部分には、以下のようなメッセージが出力されていました。
NOTE: The target instance '172.17.0.3:3306' has not been pre-provisioned (GTID set is empty). The Shell is unable to decide whether incremental distributed 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 '172.17.0.3:3306' with a physical snapshot from an existing cluster member. To use this method by default, set the 'recoveryMethod' option to 'clone'. The incremental distributed 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'.
GTIDがないみたいだけど、このまま参加していいの?それとも、既存のサーバーからコピーし直す?と聞かれています。
ここで、選択肢で「C」を選ぶと、Clone Pluginが起動して既存のサーバーから追加先のサーバーにデータがまるっとコピー&再起動が
行われます。
Please select a recovery method [C]lone/[I]ncremental recovery/[A]bort (default Clone): I
Clone Pluginは、MySQL 8.0.17から入った、新しい機能です。
MySQL InnoDB Cluster – What’s new in Shell AdminAPI 8.0.17 release
日々の覚書: MySQL 8.0.17でついにCloneプラグインが入った
これはすごいですね…。
今回は、「incremental recovery」を選んだので、現在のバイナリログに追記していく形態になります。
ここで、既存のサーバーにない他のGTIDを持ったバイナリログを持っていると、クラスタに参加するにはCloneするしかなくなります。
これが、rootユーザーを作成した時に「RESET MASTER」を使ってバイナリログをパージした理由です。
では、もうひとつのインスタンスも追加しましょう。
MySQL 172.17.0.2:33060+ ssl JS > cluster.addInstance('root@172.17.0.4') Please provide the password for 'root@172.17.0.4': ******** 〜省略〜 * Waiting for distributed recovery to finish... NOTE: '172.17.0.4:3306' is being recovered from '172.17.0.3:3306' * Distributed recovery has finished The instance '172.17.0.4' was successfully added to the cluster.
クラスタの状態を確認してみます。
MySQL 172.17.0.2:33060+ ssl JS > cluster.status() { "clusterName": "test_cluster", "defaultReplicaSet": { "name": "default", "primary": "172.17.0.2:3306", "ssl": "REQUIRED", "status": "OK", "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", "topology": { "172.17.0.2:3306": { "address": "172.17.0.2:3306", "mode": "R/W", "readReplicas": {}, "role": "HA", "status": "ONLINE", "version": "8.0.17" }, "172.17.0.3:3306": { "address": "172.17.0.3:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE", "version": "8.0.17" }, "172.17.0.4:3306": { "address": "172.17.0.4:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE", "version": "8.0.17" } }, "topologyMode": "Single-Primary" }, "groupInformationSourceMember": "172.17.0.2:3306" }
クラスタが構成できたようです。
SQLモードに変更して、Group Replicationのデータを見てみます。
MySQL 172.17.0.2:33060+ ssl JS > \sql Switching to SQL mode... Commands end with ; MySQL 172.17.0.2:33060+ ssl SQL > SELECT * FROM performance_schema.replication_group_members; +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 45c28e12-b91e-11e9-93dc-0242ac110002 | 172.17.0.2 | 3306 | ONLINE | PRIMARY | 8.0.17 | | group_replication_applier | 8889f4f6-b919-11e9-be39-0242ac110003 | 172.17.0.3 | 3306 | ONLINE | SECONDARY | 8.0.17 | | group_replication_applier | 88a0eea6-b919-11e9-b893-0242ac110004 | 172.17.0.4 | 3306 | ONLINE | SECONDARY | 8.0.17 | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ 3 rows in set (0.0008 sec)
ちなみに、デフォルトで作成したのでSingle Primary Modeですね。
では、試しにデータを作成してみましょう。
MySQL 172.17.0.2:33060+ ssl SQL > CREATE DATABASE test; Query OK, 1 row affected (0.0436 sec) MySQL 172.17.0.2:33060+ ssl SQL > use test; Default schema set to `test`. Fetching table and column names from `test` for auto-completion... Press ^C to stop. MySQL 172.17.0.2:33060+ ssl test SQL > CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL); Query OK, 0 rows affected (0.1121 sec) MySQL 172.17.0.2:33060+ ssl test SQL > INSERT INTO t1 VALUES (1, 'Luis'); Query OK, 1 row affected (0.0271 sec) MySQL 172.17.0.2:33060+ ssl test SQL > select * from t1; +----+------+ | c1 | c2 | +----+------+ | 1 | Luis | +----+------+ 1 row in set (0.0004 sec)
ひとつ目のMySQL Serverインスタンスに接続したまま、データベース、テーブルを作成してデータを投入してみました。
ここで、2つ目のインスタンスに接続してみます。
MySQL 172.17.0.2:33060+ ssl test SQL > \connect root@172.17.0.3 Creating a session to 'root@172.17.0.3' Please provide the password for 'root@172.17.0.3': ******** Fetching schema names for autocompletion... Press ^C to stop. Closing old connection... Your MySQL connection id is 35 (X protocol) Server version: 8.0.17 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one.
2つ目のMySQL Serverからも、作成したデータベースとデータを見ることができます。
MySQL 172.17.0.3:33060+ ssl SQL > use test; Default schema set to `test`. Fetching table and column names from `test` for auto-completion... Press ^C to stop. MySQL 172.17.0.3:33060+ ssl test SQL > select * from t1; +----+------+ | c1 | c2 | +----+------+ | 1 | Luis | +----+------+ 1 row in set (0.0006 sec)
なお、Single Primary Modeのため、2つ目のインスタンスはRead Onlyのためデータベースの作成などはできません。
MySQL 172.17.0.3:33060+ ssl test SQL > CREATE DATABASE test2; ERROR: 1290: The MySQL server is running with the --super-read-only option so it cannot execute this statement
OKそうですね。
Multi Primary Modeで構成してみる
では、ここで1度MySQL Serverインスタンス群を新しく作り直して、Group ReplicationをMulti Primary Modeで構成してみます。
MySQL Shellで、とりあえずひとつ目のインスタンスに接続。
MySQL JS > \connect root@172.17.0.2 Creating a session to 'root@172.17.0.2' Please provide the password for 'root@172.17.0.2': ******** Fetching schema names for autocompletion... Press ^C to stop. Your MySQL connection id is 9 (X protocol) Server version: 8.0.17 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one.
Multi Primary Modeでクラスタを作成します。「dba.createCluster」のオプションに、「multiPrimary」をtrueにして渡します。
MySQL 172.17.0.2:33060+ ssl JS > var cluster = dba.createCluster('test_cluster', { multiPrimary: true }) A new InnoDB cluster will be created on instance '172.17.0.2:3306'.
createClusterで指定できるオプションは、こちら。
MySQL Shell API / createCluster
Multi Primary Modeにすると、注意をされ、「y/N」の選択を求められます。
The MySQL InnoDB cluster is going to be setup in advanced Multi-Primary Mode. Before continuing you have to confirm that you understand the requirements and limitations of Multi-Primary Mode. For more information see https://dev.mysql.com/doc/refman/en/group-replication-limitations.html before proceeding. I have read the MySQL InnoDB cluster manual and I understand the requirements and limitations of advanced Multi-Primary Mode. Confirm [y/N]: y
Group Replicationの制限を、確認しておいてくださいね、と。
MySQL :: MySQL 8.0 Reference Manual :: 18.9.2 Group Replication Limitations
で、シードは追加できましたが、やっぱり3つインスタンスが必要だよ、と言われます。
Validating instance at 172.17.0.2:3306... This instance reports its own address as 172.17.0.2:3306 Instance configuration is suitable. Creating InnoDB cluster 'test_cluster' on '172.17.0.2: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.
というわけで、追加。
MySQL 172.17.0.2:33060+ ssl JS > cluster.addInstance('root@172.17.0.3') Please provide the password for 'root@172.17.0.3': ******** MySQL 172.17.0.2:33060+ ssl JS > cluster.addInstance('root@172.17.0.4') Please provide the password for 'root@172.17.0.4': ********
インスタンスの「mode」が、全部「R/W」になりました。
MySQL 172.17.0.2:33060+ ssl JS > cluster.status() { "clusterName": "test_cluster", "defaultReplicaSet": { "name": "default", "ssl": "REQUIRED", "status": "OK", "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", "topology": { "172.17.0.2:3306": { "address": "172.17.0.2:3306", "mode": "R/W", "readReplicas": {}, "role": "HA", "status": "ONLINE", "version": "8.0.17" }, "172.17.0.3:3306": { "address": "172.17.0.3:3306", "mode": "R/W", "readReplicas": {}, "role": "HA", "status": "ONLINE", "version": "8.0.17" }, "172.17.0.4:3306": { "address": "172.17.0.4:3306", "mode": "R/W", "readReplicas": {}, "role": "HA", "status": "ONLINE", "version": "8.0.17" } }, "topologyMode": "Multi-Primary" }, "groupInformationSourceMember": "172.17.0.2:3306" }
Group Replicationの情報をSQLで見ても、全部PRIMARYになっています。
MySQL 172.17.0.2:33060+ ssl JS > \sql Switching to SQL mode... Commands end with ; SELECT * FROM performance_schema.replication_group_members' at line 1 MySQL 172.17.0.2:33060+ ssl SQL > SELECT * FROM performance_schema.replication_group_members; +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 93e56fad-b921-11e9-8bf3-0242ac110002 | 172.17.0.2 | 3306 | ONLINE | PRIMARY | 8.0.17 | | group_replication_applier | 9747f185-b921-11e9-9736-0242ac110003 | 172.17.0.3 | 3306 | ONLINE | PRIMARY | 8.0.17 | | group_replication_applier | 9750b635-b921-11e9-9fcf-0242ac110004 | 172.17.0.4 | 3306 | ONLINE | PRIMARY | 8.0.17 | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ 3 rows in set (0.0009 sec)
確認してみましょう。ひとつ目のMySQL Serverインスタンスでデータベースを作成し、
MySQL 172.17.0.2:33060+ ssl SQL > create database test1; Query OK, 1 row affected (0.0560 sec)
2つ目のインスタンスに接続してデータベースを作成し(これは成功します)、
MySQL 172.17.0.2:33060+ ssl SQL > \connect root@172.17.0.3 Creating a session to 'root@172.17.0.3' Please provide the password for 'root@172.17.0.3': ******** Fetching schema names for autocompletion... Press ^C to stop. Closing old connection... Your MySQL connection id is 33 (X protocol) Server version: 8.0.17 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one. MySQL 172.17.0.3:33060+ ssl SQL > create database test2; Query OK, 1 row affected (0.0520 sec)
3つ目のインスタンスに接続して、作成したデータベースが全部見えることを確認。
MySQL 172.17.0.3:33060+ ssl SQL > \connect root@172.17.0.4 Creating a session to 'root@172.17.0.4' Please provide the password for 'root@172.17.0.4': ******** Fetching schema names for autocompletion... Press ^C to stop. Closing old connection... Your MySQL connection id is 26 (X protocol) Server version: 8.0.17 MySQL Community Server - GPL No default schema selected; type \use <schema> to set one. MySQL 172.17.0.4:33060+ ssl SQL > show databases; +-------------------------------+ | Database | +-------------------------------+ | information_schema | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | sys | | test1 | | test2 | +-------------------------------+ 7 rows in set (0.0016 sec)
mysql> show databases; +-------------------------------+ | Database | +-------------------------------+ | information_schema | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | sys | +-------------------------------+ 5 rows in set (0.00 sec)
OKですね。
まとめ
今回は、MySQL ShellでGroup Replicationを構成することが、なんとかできました。とりあえず、やりたいことは達成できました、と。
今度はこの構成に、MySQL Routerを追加するところをやってみましょう…。
「mysql_innodb_cluster_metadata」?
MySQL ShellのAdminAPIでクラスタを作った時は、「mysql_innodb_cluster_metadata」というデータベースができるみたいですね。
存在するテーブルは、こんな感じ。
mysql> use mysql_innodb_cluster_metadata; mysql> show tables; +-----------------------------------------+ | Tables_in_mysql_innodb_cluster_metadata | +-----------------------------------------+ | clusters | | hosts | | instances | | replicasets | | routers | | schema_version | +-----------------------------------------+ 6 rows in set (0.01 sec)
Group Replicationをこちらの手順で作った時には、このデータベースはできませんでした。
MySQL :: MySQL 8.0 Reference Manual :: 18.2.1 Deploying Group Replication in Single-Primary Mode