三流エンジニアの落書き帳

さあ、今日も未知という扉を開けてみよう

低スペックPCでもGroup Replicationを試す

気づいたら2月でした。 今年の冬は暖冬かなと思っていたら急激に寒くなってきましたね。

MySQLの開発チームはInnoDB Clusterに特に力を入れていると感じています。 マイナーバージョンが上がるにつれてどんどん便利な機能が追加されているので、常に最新の情報をキャッチアップしておく必要があります。

といってもGroup Replicationは最低でも異なるサーバ3台から構成する必要があるため、自分で検証するには少しハードルが高いです。 そこで今回は低スペックPCでもmysql-shellのsandbox機能を使えばGroup Replicationを構築できるよーということを見ていきましょう。

注意

今回は一つのPCに複数のmysql sandboxを立ててGroup Replicationを試すので必ずしもGroup Replicationのすべての機能を試せるわけではありません。 例えばFailover(Single-Primary mode)にかかる時間などネットワーク関連の本格的な検証はやはり本番環境と同じ構成で行ったほうがよいでしょう。

環境

OS:18.04.4 LTS(WSL) MySQL : 8.0.19

MySQL Serverのインストールはされていますが、起動はしていません。mysql-shellが起動すれば大丈夫です。 なお今回はインストールの仕方は割愛します。マニュアルなどをご参照ください。

MySQL :: MySQL Shell 8.0 :: 2.2 Installing MySQL Shell on Linux

目標

今回の目標はローカル環境にsandboxを複数立ち上げてGroup Replicationを構築することです。

MySQL ShellのSandbox機能を使う

mysql-shellのdbaオブジェクトにはdeploySandboxInstance()という関数があります。これはローカル環境にMySQLのsandbox環境を立ち上げてくれる便利な関数です。

引数には最低限ポート番号を指定するだけで短時間でMySQLの環境を立ち上げることが可能です。 なお関数名が長いのでタイプが面倒だと思うかもしれませんが、mysql-shellには補完機能があるためそこまで気にする必要はありません。

その他のオプションはマニュアルを見る他に下記コマンドからも参照することができます。

\? dba.deploySandboxInstance

それでは実際にsandboxを作ってみます。

koreshiki@LAPTOP-CONIPJL6:~$ mysqlsh
MySQL Shell 8.0.19

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  JS > dba.deploySandboxInstance(3000) ①
A new MySQL sandbox instance will be created on this host in
/home/koreshiki/mysql-sandboxes/3000

Warning: Sandbox instances are only suitable for deploying and
running on your local machine for testing purposes and are not
accessible from external networks.

Please enter a MySQL root password for the new instance: ②

Deploying new MySQL instance...

Instance localhost:3000 successfully deployed and started.
Use shell.connect('root@localhost:3000'); to connect to the instance.

これだけでMySQLの環境ができてしまいます。(Windowsだとファイアウォールの確認のポップアップがでてくるかもしれませんが、「アクセスを許可する」でOKです) 各sandboxに接続するためには出力結果にも書いてありますが、shell.connect('root@localhost:3000')でログインできます。(もちろん従来のmysqlクライアントでもログイン可能です)

①今回はポート番号に3000を指定してsandboxを作成しています。

②作成したsandboxのrootパスワードを聞かれます。そのままEnterを押すことでパスワードなしでrootユーザを作成できます。

なお1つのsandboxに関連するデータ(データディレクトリやpidファイル、cnfファイル)はsandboxDirオプションで指定されているディレクトリ下に作られます。今回は/home/koreshiki/mysql-sandboxes/3000という形で作られています。

同じ要領で残り2つのsandboxも作っていきます。(もちろんポート番号は重複してはいけません)

なおsandobx環境を停止させたいときはdba.stopSandboxInstance()もしくはdba.killSandboxInstance()を使います。 前者はrootのパスワードを求められて通常終了します、後者はrootのパスワードは問われず強制終了させます。 また停止しているsandboxを停止させてもデータディレクトリなどはまだ存在します。 不要であればdba.deleteSandboxInstance()でそのsandobx関連データをすべて削除できます。(事前に停止させておく必要があります。)

 MySQL  localhost:3003 ssl  JS > dba.stopSandboxInstance(3003) ①
The MySQL sandbox instance on this host in
/home/koreshiki/mysql-sandboxes/3003 will be stopped

Please enter the MySQL root password for the instance 'localhost:3003': ②

Stopping MySQL instance...

Instance localhost:3003 successfully stopped.

 MySQL  JS > \! ls -l /home/koreshiki/mysql-sandboxes/3003 ③
total 4
drwxrwxr-x 1 koreshiki koreshiki 512 Feb  8 11:49 bin
drwxrwxr-x 1 koreshiki koreshiki 512 Feb  8 11:49 lib
-rw------- 1 koreshiki koreshiki 736 Feb  8 11:49 my.cnf
drwxrwxr-x 1 koreshiki koreshiki 512 Feb  8 11:49 mysql-files
drwxr-x--- 1 koreshiki koreshiki 512 Feb  8 11:52 sandboxdata
-rwx------ 1 koreshiki koreshiki 294 Feb  8 11:50 start.sh
-rwx------ 1 koreshiki koreshiki 191 Feb  8 11:50 stop.sh

 MySQL  JS > dba.deleteSandboxInstance(3003) ④

Deleting MySQL instance...

Instance localhost:3003 successfully deleted.

 MySQL  JS > \! ls -l /home/koreshiki/mysql-sandboxes/3003 ⑤
ls: cannot access '/home/koreshiki/mysql-sandboxes/3003': No such file or directory
ERROR: System command "ls -l /home/koreshiki/mysql-sandboxes/3003" returned exit code: 2.

①sandboxを停止します。

②rootパスワードを入力する必要があります。(killSandboxInstanceであれば不要です)

③停止しただけではデータディレクトリなどは削除されません。

④sandboxを完全に削除します。

⑤完全にデータを削除できたことが確認できます。

Group Replicationを構築していく

さて必要なインスタンスは準備できたのでGroup Replicationを構築してきます。 ここでもmysql-shellを使うことで比較的簡単に構築することができます。

簡単に手順を整理しておきましょう。 ①dba.checkInstanceConfigurationでGroup Replicationに必要な条件を満たすかチェック

①´必要に応じてdba.configureInstanceを使って①でエラーとなった箇所の修正

インスタンスを1つ選択してdba.createCluster()を使ってクラスターを作成する

③残りのインスタンスをCluster.addInstance()を使ってクラスターに追加する

では早速試していきましょう。

設定の確認及び修正

 MySQL  JS > dba.checkInstanceConfiguration('root@localhost:3000') ①
Validating local MySQL instance listening at port 3000 for use in an InnoDB cluster...
NOTE: Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as 127.0.0.1:3000

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                                             |
+--------------------------+---------------+----------------+--------------------------------------------------+
| binlog_checksum          | CRC32         | NONE           | Update the server variable                       |
| enforce_gtid_consistency | OFF           | ON             | Update read-only variable and restart the server |
| gtid_mode                | OFF           | ON             | 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",
            "current": "CRC32",
            "option": "binlog_checksum",
            "required": "NONE"
        },
        {
            "action": "server_update+restart",
            "current": "OFF",
            "option": "enforce_gtid_consistency",
            "required": "ON"
        },
        {
            "action": "restart",
            "current": "OFF",
            "option": "gtid_mode",
            "persisted": "ON",
            "required": "ON"
        }
    ],
    "status": "error"
}

①dba.checkInstanceConfigurationの引数にはURIを指定します。

②修正すべき設定があるとそれを列挙してくれます。

③設定を修正するためにはdba.configureInstance()を使ってねということですね。

④問題がある設定を変数名と現在の値および必要な設定値およびそれを修正に必要なアクションがJSON形式で出力されます。

例えばbinlog_checksumの修正にはその変数のアップデートだけで十分ですが、gtid_modeの修正にはサーバ再起動が必要だとわかりますね。

今回はわざとエラーが返ってくるように事前に変数をいじっています。

 MySQL  JS > dba.configureInstance('root@localhost:3000') ①
Configuring local MySQL instance listening at port 3000 for use in an InnoDB cluster...
NOTE: Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as 127.0.0.1:3000

NOTE: Some configuration options need to be fixed: ②
+--------------------------+---------------+----------------+--------------------------------------------------+
| Variable                 | Current Value | Required Value | Note                                             |
+--------------------------+---------------+----------------+--------------------------------------------------+
| binlog_checksum          | CRC32         | NONE           | Update the server variable                       |
| enforce_gtid_consistency | OFF           | ON             | Update read-only variable and restart the server |
| gtid_mode                | OFF           | ON             | Restart the server                               |
+--------------------------+---------------+----------------+--------------------------------------------------+

Some variables need to be changed, but cannot be done dynamically on the server.
Sandbox MySQL configuration file at: /home/koreshiki/mysql-sandboxes/3000/my.cnf
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 '127.0.0.1:3000' was configured to be used in an InnoDB cluster.
Restarting MySQL... ⑤
NOTE: MySQL server at 127.0.0.1:3000 was restarted.

MySQL  JS > dba.checkInstanceConfiguration('root@localhost:3000') ⑥
Validating local MySQL instance listening at port 3000 for use in an InnoDB cluster...
NOTE: Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as 127.0.0.1:3000

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 '127.0.0.1:3000' is valid to be used in an InnoDB cluster.

{
    "status": "ok" ⑦
}

①dba.configureInstanceで必要な修正を行えます。引数にはURIを指定します。

②修正が必要な変数が列挙されます。

③設定を修正するか確認されるのでyを選択します。

インスタンスを再起動させるか確認されるのでyを選択します。(設定によっては再起動しないと反映されないものがあるため)

⑤再起動されたことが確認できます。

⑥再度dba.checkInstanceConfigurationで設定が正常が確認します。

⑦OKが出力されればOKです。

クラスターを作成する

残りの2インスタンスについても設定の確認を終えていよいよクラスターを作っていきます。

 MySQL  JS > \c root@localhost:3000 ①

 MySQL  localhost:3000 ssl  JS > var c = dba.createCluster('myCluster') ②
A new InnoDB cluster will be created on instance 'localhost:3000'.

Validating instance configuration at localhost:3000...
NOTE: Instance detected as a sandbox. ③
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as 127.0.0.1:3000

Instance configuration is suitable.
NOTE: Group Replication will communicate with other members using '127.0.0.1:30001'. Use the localAddress option to override.

Creating InnoDB cluster 'myCluster' on '127.0.0.1:3000'...

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  localhost:3000 ssl  JS > c.status() ⑤
{
    "clusterName": "myCluster",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "127.0.0.1:3000",
        "ssl": "REQUIRED",
        "status": "OK_NO_TOLERANCE",
        "statusText": "Cluster is NOT tolerant to any failures.",
        "topology": {
            "127.0.0.1:3000": {
                "address": "127.0.0.1:3000",
                "mode": "R/W",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            }
        },
        "topologyMode": "Single-Primary"
    },
    "groupInformationSourceMember": "127.0.0.1:3000"
}

①まずはどこでもいいのでどこかのインスタンスに接続します。

②dba.createClusterでクラスターを新規作成します。引数にはクラスター名を渡します。 今回の場合createClusterで作成したクラスターオブジェクトを変数cに渡しています。

③今回はインスタンスがsandboxなためNOTEとして出力されます。

クラスターには最低3台必要だよと言っています。

⑤Cluster.status()でクラスターのステータスを確認します。引数に{extended:true}を指定するとより詳細な内容を確認できます。

クラスターにインスタンスを追加していく

 MySQL  localhost:3000 ssl  JS > c.addInstance('root@localhost:3001') ①

NOTE: The target instance '127.0.0.1:3001' 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 '127.0.0.1:3001' 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): I ②
NOTE: Group Replication will communicate with other members using '127.0.0.1:30011'. Use the localAddress option to override.

Validating instance configuration at localhost:3001...
NOTE: Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as 127.0.0.1:3001

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.
State recovery already finished for '127.0.0.1:3001'

The instance 'localhost:3001' was successfully added to the cluster.

 MySQL  localhost:3000 ssl  JS > c.status() ③
{
    "clusterName": "myCluster",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "127.0.0.1:3000",
        "ssl": "REQUIRED",
        "status": "OK_NO_TOLERANCE",
        "statusText": "Cluster is NOT tolerant to any failures.",
        "topology": {
            "127.0.0.1:3000": {
                "address": "127.0.0.1:3000",
                "mode": "R/W",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            },
            "127.0.0.1:3001": { ④
                "address": "127.0.0.1:3001",
                "mode": "R/O",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            }
        },
        "topologyMode": "Single-Primary"
    },
    "groupInformationSourceMember": "127.0.0.1:3000"
}

①Cluster.addInstance()でクラスターにインスタンスを追加できます。引数には対象のURIを指定します。

②異なるGTIDを持っている場合リカバリする必要があります。CはCloneプラグインを使って、Iは増分だけ、Aはリカバリをしないから選択します。今回は増分リカバリを選択しました。もちろんCloneでもOKです。

③Cluster.status()でクラスターの状態を確認します。

localhost:3001が追加されていることがわかります。

同じ要領で3つ目も追加してきます。

最終的に次のようにクラスターが完成しました!

 MySQL  localhost:3000 ssl  JS > c.status()
{
    "clusterName": "myCluster",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "127.0.0.1:3000",
        "ssl": "REQUIRED",
        "status": "OK",
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
        "topology": {
            "127.0.0.1:3000": {
                "address": "127.0.0.1:3000",
                "mode": "R/W",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            },
            "127.0.0.1:3001": {
                "address": "127.0.0.1:3001",
                "mode": "R/O",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            },
            "127.0.0.1:3002": {
                "address": "127.0.0.1:3002",
                "mode": "R/O",
                "readReplicas": {},
                "replicationLag": null,
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.19"
            }
        },
        "topologyMode": "Single-Primary"
    },
    "groupInformationSourceMember": "127.0.0.1:3000"
}

慣れれば数分~数十分でGroup Replicationを構築することができます。

まとめ

  • mysql-shellのsandboxを使えばローカル環境にMySQL環境をすぐに立ち上げることができる
  • それらを使えば低スペックのPCでもGroup Replicationを簡単に試すことができる

皆さんもぜひGroup Replicationを試してみてください!