こんにちは、さくらインターネットの鷲北です。
もうずいぶん前になりますが、研究所ブログでは MariaDB Galera Clusterを試す(1)、(2)、(3) というシリーズで master/master 構成のデータベース・クラスタが簡単に組めるGalera Clusterというシステムを紹介しました。あれから6年が過ぎてしまい、システムはアップデートされているのに記事は古いままなので、ぼちぼち書き直すかということで、今回はPXC(Percona XtraDB Cluster)をご紹介したいと思います。
PXC(Percona XtraDB Cluster)とは
PXCは、Percona社が開発を主導するオープンソースのデータベース・クラスタ・システムです。中核となるデータベースはMySQLで、これをGalera Clusterによってクラスタ化しています。昔の記事ではMariaDBをクラスタ化していましたが、PXCはMySQLを master/master でクラスタ化している点が特徴となります。これは、シングルや master/slave 構成のMySQLデータベースから、ごく容易に移行ができるという点で優れているということを意味します。
Galera Clusterの部分は、以前の記事から格段に進化しています。とはいえ、基本原理は変わっていません。改めて記載するとこんな感じです。
- Galera Replicationが複数のRDBMをレプリケートするwsrep APIを提供し、ノード間の同期を取ります
- 完全同期型であるため、すべてのノードがアクティブかつマスターとなります
- ノードのどれに対してもリード/ライトが可能です
- ノードの追加/削除は非常に簡単です
- クライアント接続は単体のMySQLとなんら変わりなく行えます
ここでは運用面でどのように変化したのか、インストールや起動操作がどう変わったか(楽になったか)を説明したいと思います。特にCentOSが7.xになっていますので、その辺も含めてアップデートしておきましょう。
インストール手順
以前の記事では、クラスタを構成した上でバランサなども配置したのですが、今回はシンプルにPXCのみインストールする手順を示します。
- 例によってさくらのクラウドを使用
- サーバスペックは適当に。OSは CentOS 7.6
出来上がったクラスタをどのようにバランスさせるかは、それぞれお好みで設定してください。
また、Percona社は非常によくできたドキュメントをオンラインで公開しています。今回の手順も基本的には Quick Start Guide をお手本に説明しているだけになっています。ですので本稿は簡単な日本語訳と思ってご覧いただければと思います。
まず始めに、今回のクラスタのサーバ構成を示しておきます。サーバの配置とIPアドレスの割り当てはこんな感じです。
ノード1、2、3に、それぞれdb1、db2、db3というホスト名を付け、IPアドレスを192.168.100.11、12、13と振ることにします。ネットワーク設定等の基本的なインストールは省略します。NATを超えてyum updateできるように適切に設定してください。その上で、OSを最新版にしておくために、以下のようにアップデートを忘れずに実行しておいてください。
# yum -y update # reboot
それからもうひとつ、PXCは4つのポート番号に対するアクセスが必要になります。今回は簡単に、次のようにして開放します。
# firewall-cmd --permanent --add-port=3306/tcp # firewall-cmd --permanent --add-port=4444/tcp # firewall-cmd --permanent --add-port=4567/tcp # firewall-cmd --permanent --add-port=4568/tcp # firewall-cmd --reload
特定IPアドレスからのアクセス制限、のような工夫は各自で行ってください。
第1ノードの設定
まず最初に、クラスタの第1ノードを設定します。db1から始めましょう。
PXCのインストールはyumのリポジトリで簡単に行えます。以下のように入力してください。
[root@db1 ~]# yum -y install https://repo.percona.com/yum/percona-release-latest.noarch.rpm [root@db1 ~]# yum -y install Percona-XtraDB-Cluster-57
次にMySQLの設定ファイルを確認・検討します。PXCのパッケージでは、設定ファイルは /etc/my.cnf.d と /etc/percona-xtradb-cluster.conf.d ディレクトリに分かれているので、MySQLの設定は前者に、PXCの設定は後者に置くとよいでしょう。つまりサーバスペックにあわせたMySQLの設定は /etc/my.cnf.d/my.cnf ファイルを作成して以下のように記述します。
[mysqld] max_connections=100 innodb_file_per_table=ON innodb_buffer_pool_size=1G innodb_log_file_size=64M innodb_flush_method=O_DIRECT # その他、コア数やメモリ容量に合わせてお好みのチューニングをどうぞ
チューニングをする際に注意点がひとつあります。それはPXCの動作の前提として log-bin オプションが必須となっていることです。パフォーマンスアップのために無効化することがないようにしてください。
/etc/percona-xtradb-cluster.conf.d ディレクトリには3つの設定ファイルが格納されていますが、この時点ではまだ何もする必要がありませんので、そのままにしておいてください。
さてmy.cnfの設定が終わったら、最初にシングルノードとして起動し、データベースのrootパスワードを設定します。PXCは、最初の起動時にランダムなパスワードを設定し、それをログファイルに記録しています。これを以下の手順で確認してDBにログインします。
[root@db1 ~]# systemctl start mysql [root@db1 ~]# grep 'temporary password' /var/log/mysqld.log 2019-04-11T02:35:03.340804Z 1 [Note] A temporary password is generated for root@localhost: ********** [root@db1 ~]# mysql -u root -p Enter password: ********** Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 11 Server version: 5.7.25-28-57-log Copyright (c) 2009-2019 Percona LLC and/or its affiliates Copyright (c) 2000, 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 '\h' for help. Type '\c' to clear the current input statement. mysql>
ログインできたら、初期パスワードから自分の好きなパスワードへ変更します。
mysql> alter user 'root'@'localhost' identified by 'ROOT_PASSWORD';
もうひとつ、sstuserという名前のユーザを作成ます。sstuserとは、Galera Clusterがデータベースを同期するときに使うユーザです。ここでパスワードを設定し、後ほど wsrep_sst_auth という設定項目で指定しますのでメモしておいてください。
mysql> create user 'sstuser'@'localhost' identified by 'SST_PASSWORD'; mysql> grant reload, lock tables, process, replication client on *.* to 'sstuser'@'localhost'; mysql> \q
ここまで完了したら、いったんMySQLサーバを停止します。
[root@db1 ~]# systemctl stop mysql
第1ノードの起動
続いて、第1ノードのPXCとしての設定、Galera Clusterとしての設定を行います。設定ファイルは /etc/percona-xtradb-cluster.conf.d/wsrep.cnf ですので、これを編集します。変更するべきポイントは以下の通りです。
- wsrep_cluster_address
- 全ノードのIPアドレスを列挙します。形式は「gcom://」に続けて、カンマで区切ったIPアドレスの列になります。あらかじめ決めたクラスタサーバのIPアドレスを列挙してください。
- wsrep_slave_threads
- レプリケーション・トランザクションをどの程度並列動作させるかを指定します。大きくするほど並列数が多くなり、スループットは向上します。あまり大きくしすぎるとDB一貫性が損なわれることがあり、その場合は1に戻す必要があります。詳しい議論はマニュアルを参照するか、CHECKING THE REPLICATION HEALTH を読んでみてください。迷うようでしたら、パッケージの初期値の8のままで大丈夫だと思います。
- wsrep_cluster_name
- クラスタの識別子です。お好みの名前を1つ決めて、名づけてください。ここでは pxc-cluster とします。
- wsrep_node_address, wsrep_node_name
- ノードのIPアドレスとノード名を記載します。ここではそれぞれ192.168.100.11、db1 です。
- wsrep_sst_auth
- Galera Clusterがデータベースの同期を行うときにパスワード認証を必要とするのですが、そのときのパスワードを指定します。これは最初のMySQLの起動のとき、sstuserのパスワードとして設定したものと同じ文字列を指定します。メモした通りに記述してください。
wsrep_cluster_address=gcomm://192.168.100.11,192.168.100.12,192.168.100,13 wsrep_slave_threads=8 wsrep_cluster_name=pxc-cluster wsrep_node_address=192.168.100.11 wsrep_node_name=db1 wsrep_sst_auth=sstuser:SST_PASSWORD
設定ファイルが完成したら、第1ノードを起動します。クラスタの第1ノードを起動するときは、サービス名に「@bootstrap.service」を付加して必ず次のコマンドを使います。
[root@db1 ~]# systemctl start mysql@bootstrap.service
「@bootstrap.service」を付加することによって、クラスタの最初のノードとして起動することができます。これを忘れると、既存のクラスタに参加しようとして探すモードになってしまうため、起動に失敗しますので注意してください。
起動に成功したら、MySQLを実行してクラスタの状態を確認してみましょう。以下のようにすると状態を確認することができます。多数の状態変数が表示されますが、重要なパラメータのみ抜粋してみます。
[root@db1 ~]# mysql -u root -p mysql> show status like 'wsrep%'; +----------------------------------+--------------------------------------+ | Variable_name | Value | +----------------------------------+--------------------------------------+ | ... | ... | | wsrep_local_state | 4 | | wsrep_local_state_comment | Synced | | ... | ... | | wsrep_incoming_addresses | 192.168.100.11:3306 | | ... | ... | | wsrep_cluster_size | 1 | | ... | ... | | wsrep_cluster_status | Primary | | wsrep_connected | ON | | ... | ... | | wsrep_ready | ON | +----------------------------------+--------------------------------------+ 71 rows in set (0.00 sec) // 一部抜粋
特に、wsrep_cluster_size が 1 で wsrep_incoming_addresses が db1 を間違いなく指していればOKです。
第2、第3ノードの起動
第1ノードが起動したら、第2ノード以降を順に起動していきます。第2ノードの起動手順をおおまかに示します。
- 第1ノード設定と同様に、yumでPXCをインストールするところまでは同じです
- my.cnf はまったく同じものを用意します。差異があると動作に支障をきたすので、完全に同じにすることをお勧めします
- 第1ノードではrootユーザのパスワード設定のために一度起動しましたが、第2ノードではその必要はありません。クラスターに参加するときに同期して、システムパラメータも上書きしてしまうからです
- wsrep.cnf は wsrep_node_address と wsrep_node_ip のみを適切に書き換えます。他のパラメータは差異がないように注意してください
ソフトウェアの準備が済んだら起動します。今度はdb1が起動しているので、既存のクラスタに参加するために以下のコマンドラインで起動します。
[root@db2 ~]# systemctl start mysql
無事に起動すると、db2にもdb1と同じパスワードでログインできます。
[root@db2 ~]# mysql -u root -p mysql> show status like 'wsrep%'; +----------------------------------+-----------------------------------------+ | Variable_name | Value | +----------------------------------+-----------------------------------------+ | ... | ... | | wsrep_local_state | 4 | | wsrep_local_state_comment | Synced | | ... | ... | | wsrep_incoming_addresses | 192.168.100.12:3306,192.168.100.11:3306 | | ... | ... | | wsrep_cluster_size | 2 | | ... | ... | | wsrep_cluster_status | Primary | | wsrep_connected | ON | | ... | ... | | wsrep_ready | ON | +----------------------------------+-----------------------------------------+ 71 rows in set (0.01 sec)
第3ノードも、同じ手順を繰り返すことで追加できます。追加するごとにステータスを確認し、クラスタサイズとIPアドレスをチェックしていきましょう。
[root@db3 ~]# mysql -u root -p mysql> show status like 'wsrep%'; +----------------------------------+-------------------------------------------------------------+ | Variable_name | Value | +----------------------------------+-------------------------------------------------------------+ | ... | ... | | wsrep_local_state | 4 | | wsrep_local_state_comment | Synced | | ... | ... | | wsrep_incoming_addresses | 192.168.100.12:3306,192.168.100.13:3306,192.168.100.11:3306 | | ... | ... | | wsrep_cluster_size | 3 | | ... | ... | | wsrep_cluster_status | Primary | | wsrep_connected | ON | | ... | ... | | wsrep_ready | ON | +----------------------------------+-------------------------------------------------------------+ 71 rows in set (0.00 sec)
ここまでくれば、3台のクラスタが完成です。
動作チェック
では master/master データベースとして動作しているか、チェックしてみましょう。まず db1 でデータベースを作成してみます。
[root@db1 ~]# echo 'create database testdb;' | mysql -u root -p
次に db2 で、テーブルを作成します。
[root@db2 ~]# echo 'use testdb; create table test ( id int primary key, name varchar(30));' | mysql -u root -p
続いて db3 でデータを書き込みます。
[root@db3 ~]# echo 'insert into testdb.test values (1, "pxc");' | mysql -u root -p
最後に db1 で読み出してみます。
[root@db1 ~]# mysql -u root -p mysql> select * from testdb.test; +----+------+ | id | name | +----+------+ | 1 | pxc | +----+------+ 1 row in set (0.00 sec)
言うまでもありませんが、どのノードでどんなコマンドを実行しても、等しく同じ結果が得られます。