MySQLでマルチマスタクラスタリングが出来る選択肢としてGaleraと言うやつがある。
マルチマスタってのは、基本的なマスタ・スレーブ式のreplicationじゃなく、メンバー全てがマスタとして動作できるって事で、どのサーバに書き込んでも他のサーバに同期される。
ロック問題とかさえ回避できれば比較的簡単に冗長性や性能を上げることができる夢のような話だけど、実際は書き込みのオーバーヘッドは結構大きいんで、性能は参照中心の構成じゃ無いとあまり上がらないんだけど、ノードが落ちたとしても何も手を入れずにシステムが勝手に動き続けるんで、利点は結構大きい。
そんなわけで、今回、Galeraを構築してみた。
GaleraはMySQLのモジュールで、Percona XtraDB ClusterとかMariaDB Galera Clusterみたいなソリューションで使える。
以前は大きめのシステムでPerconaを使っていたんだけど、AWSがMariaDBを提供しているんで(Galera Clusterは提供してないけど)、MariaDBの方で構築してみた。
ベース環境はCentOS6のお名前.com VPSに構築。
yumのリポジトリが提供されているので、それを登録してインストールする。
/etc/yum.repos.d/にMariaDB.repoみたいな感じで登録
1 2 3 4 5 |
[mariadb] name = MariaDB baseurl = http://yum.mariadb.org/10.2/centos6-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1 |
で、yumでInstall
1 |
yum install MariaDB-server galera |
でもって、galeraに関する設定を書く
/etc/my.cnf.d/server.cnf
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[mysqld] wsrep_on=ON wsrep_cluster_name=MyCluster wsrep_cluster_address=gcomm://192.168.0.10,192.168.0.11,192.168.0.12 wsrep_node_address= wsrep_provider='/usr/lib64/galera/libgalera_smm.so' wsrep_sst_method=rsync wsrep_slave_threads=2 default_storage_engine=InnoDB binlog_format=ROW innodb_autoinc_lock_mode=2 innodb_locks_unsafe_for_binlog=1 log_bin=mysql-bin |
wsrepってのがGaleraでreplicationする設定系
wsrep_onはそのままクラスタリングを有効化するオプション、書き忘れると動作しない。
wsrep_cluster_nameに管理用のクラスタ名
wsrep_cluster_addressはクラスタメンバのIP一覧
立ち上げ時に、このIPのサーバに接続してクラスタに参加する。
一番最初に立ち上げるサーバには既存サーバが無いんで、wsrep_cluster_address=gcomm:// で、最初のサーバであることを宣言する。
ただ、クラスタが稼働した後に再起動したときとかに、既存のクラスタに参加出来ないと面倒になるんで、cnfにはメンバになる予定の一覧を書いておいて、initスクリプトを呼び出すときに、コマンド引数で–wsrep_cluster_address=gcomm:// を付けて最初のノードを立ち上げる。
あと、追加ノードが立ち上がる時は、ここに書かれたノードからデータを取ってきて初回同期が発生する(通常のマスタ・スレーブみたいにサーバをロックしてファイルコピーしてとかしないでも勝手に同期する)んだけど、参照されたサーバは更新停止するんで、データが増えてからノードを追加するときは、コマンドラインオプションで空いてるサーバを指定して立ち上げるのがオススメ。
wsrep_node_addressは、自分のアドレスを記入するんだけど、最初のネットワークアダプタのアドレスで良ければ空でも大丈夫。
wsrep_provider=’/usr/lib64/galera/libgalera_smm.so’は、ほぼ固定のおまじないで、replicationに使うGaleraライブラリのパスを指定。
wsrep_sst_method=rsyncは、先に書いた初回時に同期するときの方法で、今回はブロックされるけど高速なrsyncによる方法を選択。
wsrep_slave_threads=2は、replicationスレーブ動作に使うスレッド数。 お名前3コアなんで、2コアにしておいた。
default_storage_engine=InnoDBは直接の設定では無いんだけど、Galera Clusterの制限として、InnoDBしか同期できない(MyISAMとかはダメ)んで、InnoDBを選択。
binlog_format=ROW
innodb_autoinc_lock_mode=2
log_bin=mysql-bin
ここらもセット物なんだけど、Galera Clusterでは行フォーマットのBinlogで同期する仕組みなんで、Binlogもそうなるように指定。
あと、マルチマスタってAutoincrementするとき複数のサーバで同時に発生して重複すると不整合を起こしかねないんで、それを上手くやって貰う為にautoinc_lock_modeは2を指定する事になっている。 このセットはmustなんで手を入れない。
binlogのExpiresとかは普通に指定してOK。
で、あとはservice mysql startしてやれば立ち上がる。
第1ノード:
1 |
service mysql start --wsrep_cluster_address=gcomm:// |
第2ノード:
1 |
service mysql start --wsrep_cluster_address=gcomm://第1ノードIP |
第3ノード:
1 |
service mysql start --wsrep_cluster_address=gcomm://第2ノードIP |
みたいにやっていく。
無事にクラスタに参加出来ていると、MySQL状態変数wsrep_incoming_addressesにノードがどんどん増えていくんで、各段階で
1 |
mysql -e "show status like 'wsrep_incoming_addresses'" |
とかやるとノードが増えていくのを見られる。 そして、どっかのノードを落とすとそれが勝手に消えていくし、再起動するとまた沸く。
この状態で、どこかのノードでSQL更新するとほぼ即座(お名前VPSでの実測で1ms未満)ですぐに他のノードでもそのデータが取れた。
クラスタリングを前提に作っていないアプリケーションでも、ロックさえ気をつければ素敵に広げていける。
今回、試しに入れたシステムがクラスタリング前提じゃ無かったんで、管理的なスクリプトをサーバで直実行する仕組みなんだけど、複数のサーバで実行されると困る(別のサーバにレポーティングするため)んで、どうしようかと思ったけど、状態変数のwsrep_local_indexって言うところに、クラスタ内での自身の順序(クラスタに参加した順序だけど、途中で落ちたりすると飛ばされて後ろに再度並ぶ)が入っているので、この値を取って0の時だけ実行するという条件追加で回避できた。
ノード追加時に手動で同期したりしないでも勝手によろしくやってくれるのはかなり便利。 クラウドとかでノンストップで拡張するときとか、クラスタになっていればインスタンス追加で増やすことも出来るし、インスタンスモデルを切り替える時にも止めやすいんでとりあえず組んでおくと幸せになれる感じがする。
(977)