2014.10.10

クラスタ復旧時の順番が大切 MariaDB Galera Clusterの障害復旧方法

Pocket

はじめに

こんにちは。次世代システム研究室の チャン ドゥック ウィです。
VMの障害でサーバがダウン、通信障害でMariaDB Galera Clusterが崩壊するトラブルは、ある日突然訪れます。
復旧手順を知っていれば、すぐに復旧できたのに、マニュアルはなく、インタネットの情報が少ないため、痛い目にあった人は少なくありません。
障害が起きたときに速やかに復旧できるよう、当ブログでは、MariaDB Galera Clusterの障害復旧方法を紹介したいと思います。

MariaDB Galera Clusterのノードにおける障害の原因

MariaDB Galera Clusterのノードにおける障害の原因が様々ありますが、主な原因として考えられるものは以下の3種類です。
1.ハードウェア障害(ハードディスク容量がなくなるなど)
2.ソフトウェアのクラッシュ(プロセス異常など)
3.通信障害(VMの障害でサーバがダウン、途中でファイルウォールの設定が不正、ネットワークの設定が不正になるなど)

1と2の原因で、クラスタから単一のノードに障害が発生するとき、ハードウェアやソフトウェアの障害を対応した後、以下のコマンドでMariaDBノードを再起動することで、自動で復旧可能です。同期処理に関するイベント内容は、mysqlエラーログで確認できます。
/etc/mariadb/cluster/mysql.server start
全ノードに及ぶ障害の場合は、クラスタを組み直す必要がありますので、今回のブログはこのような障害から復旧する方法を説明したいと思います。

当ブログで使用するクラスタ構成と障害状況

構成は以下の通りです

MariaDB Galera Clusterクラスタの構成
IPアドレス OS MariaDBバージョン Galera Clusterバージョン
1台目 192.168.0.1 CentOS 6.5 Mariadb Server 5.5.37 MariaDB Galera Cluster 5.5
2台目 192.168.0.2 CentOS 6.5 Mariadb Server 5.5.37 MariaDB Galera Cluster 5.5
3台目 192.168.0.3 CentOS 6.5 Mariadb Server 5.5.37 MariaDB Galera Cluster 5.5

障害状況

途中でVMの障害でサーバがダウンして、ネットワークの通信障害が発生しまったため、全ノードに影響が及びクラスタが崩壊してしまいました。

復旧方法

今回、クラスタを復旧する作業を中心に説明したいので、通信障害を対応したことは前提です。
また、クラスタが崩壊してしまうので、クラスタを組み直す必要があります。
最新データを持っているノードを探し、そのノードはクラスタの初期ノードとして起動します。
2台目と3台目も順次起動することでクラスタを復旧できます。

Step 1.クラスタ全ノードを停止する

クラスタが崩壊してしまうため、単一のノードでデータベースを確認できない可能性が高いです。
データベースを選択すると、以下のエラーが発生し、データベースの操作ができません。
use test_cluster;
ERROR 1047 (08S01): WSREP has not yet prepared node for application use
このような状況になる場合、クラスタを組み直す必要があるので、まず、全ノードを停止します。
/etc/mariadb/cluster/mysql.server stop
Shutting down MySQL... SUCCESS!

Step 2. 最新データを持っているノードを探す

MariaDB Galera Clusterを復旧するときに、古いデータを持っているノードが初期ノードとして、クラスタを組みなおすと、
2台目が起動するとき、以下のエラーが発生してうまく起動できない場合があります。
[ERROR] WSREP: Local state seqno (2323) is greater than group seqno (2322): 
states diverged. Aborting to avoid potential data loss. 
Remove '/mnt/mariadb/cluster/grastate.dat' file and restart if you wish to continue. (FATAL)
「/mnt/mariadb/cluster/grastate.dat」というファイルを削除することで、2台目をクラスタに追加する可能ですが、
データがロストする可能性が高いので要注意です。
最新データを持っているノードを探すため、各サーバーに以下のコマンドを実行し、wsrep_last_committedを確認します。
/etc/mariadb/cluster/mysql.server start --wsrep-new-cluster
show status like 'wsrep%';
/etc/mariadb/cluster/mysql.server stop

【192.168.0.1】
+------------------------------+--------------------------------------+
| Variable_name                | Value                                |
+------------------------------+--------------------------------------+
| wsrep_local_state_uuid       | 79cff355-2da7-11e4-b83d-5eafba047adc |
| wsrep_protocol_version       | 5                                    |
| wsrep_last_committed         | 2323                                 |★

【192.168.0.2】
+------------------------------+--------------------------------------+
| Variable_name                | Value                                |
+------------------------------+--------------------------------------+
| wsrep_local_state_uuid       | 79cff355-2da7-11e4-b83d-5eafba047adc |
| wsrep_protocol_version       | 5                                    |
| wsrep_last_committed         | 2323                                 |

【192.168.0.3】
+------------------------------+--------------------------------------+
| Variable_name                | Value                                |
+------------------------------+--------------------------------------+
| wsrep_local_state_uuid       | 79cff355-2da7-11e4-b83d-5eafba047adc |
| wsrep_protocol_version       | 5                                    |
| wsrep_last_committed         | 2322                                 |
Galera Clusterはスプリットブレイン対策としてQuorum方式を採用しています。
クラスタを構成するノードの過半数とコミュニケーションが取れていない場合、
自身がネットワークから切り離されているとみなして全ての操作を拒否するようになります。
というわけで、全部3台のクラスタの場合、2台が落ちたら、3台目も動かなくなっているので、
最大値を持っているサーバーが2台あるはずです。
この2台サーバーは初期サーバーと2台目としてスタートしたら問題なくクラスタ全部復旧できます。
※優先順位に関しては、wsrep_last_committedの大きいサーバーが先に起動します。上記の例で、ノードの起動順位が
①192.168.0.1(初期ノード)、②192.168.0.2、③192.168.0.3になるでしょう。

Step 3. replicaアカウントに正しい権限とパスワードを設定する

クラスタを組みなおすためのアカウントを作成する。既にアカウントがあれば、このステップをスキップしても問題ありません。
※念のため、3台にもアカウントを追加しましたが、初期のサーバーのみ追加しても問題ないです。
grant all on *.* to replica@localhost identified by 'secret_pass';
grant all on *.* to replica@192.168.0.1 identified by 'secret_pass';
grant all on *.* to replica@192.168.0.2 identified by 'secret_pass';
grant all on *.* to replica@192.168.0.3 identified by 'secret_pass';

MariaDB [(none)]> grant all on *.* to replica@192.168.0.1 identified by 'secret_pass';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> grant all on *.* to replica@192.168.0.2 identified by 'secret_pass';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> grant all on *.* to replica@192.168.0.3 identified by 'secret_pass';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> select host,user from mysql.user where user='replica';
+-------------+------------+
| host           | user    |
+----------------+---------+
| 192.168.0.1    | replica |
| 192.168.0.2    | replica |
| 192.168.0.3    | replica |
| localhost      | replica |
+----------------+---------+
4 rows in set (0.00 sec)

Step 4.各DBサーバーに認証情報を追加する

【192.168.0.1】
vi /etc/mariadb/cluster/my.cnf
wsrep_node_name='db01' #192.168.0.1のDBサーバー
wsrep_sst_auth=replica:secret_pass
wsrep_sst_method=rsync #rsyncで同期する場合のみ、設定します

【192.168.0.2】
vi /etc/mariadb/cluster/my.cnf
wsrep_node_name='db02' #192.168.0.2のDBサーバー
wsrep_sst_auth=replica:secret_pass
wsrep_sst_method=rsync

【192.168.0.3】
vi /etc/mariadb/cluster/my.cnf
wsrep_node_name='db03' #192.168.0.3のDBサーバー
wsrep_sst_auth=replica:secret_pass
wsrep_sst_method=rsync
※wsrep_sst_methodで同期方法を設定可能です。以下でGalera Clusterが3同期方法を対応しています
MariaDB Galera Clusterの同期メソッド
同期メソッド 同期速度 Donorをブロック? Available on Live Node 種類
rsync 一番速い × physical
xtrabackup 速い × physical
mysqldump 遅い × logical|donor and joiner
同期方法ごとにメリットとデメリットがありますが、今回はデータ量が多すぎて、復旧の時間を優先するため、rsyncメソッドを選びました。
同期方法の詳細については、Galera Clusterのマニュアルを参考してください。

Step 5.初期ノード(192.168.0.1)を起動する

/etc/mariadb/cluster/mysql.server start --wsrep-new-cluster
Starting MySQL.... SUCCESS!
確認する(一部抜粋)
MariaDB [(none)]> show status like 'wsrep%';
+------------------------------+--------------------------------------+
| Variable_name                | Value                                |
+------------------------------+--------------------------------------+
| wsrep_local_state_uuid       | 79cff355-2da7-11e4-b83d-5eafba047adc |
| wsrep_protocol_version       | 5                                    |
| wsrep_last_committed         | 2323                                 |
| wsrep_local_state_comment    | Synced                               |
| wsrep_incoming_addresses     | 192.168.0.1:3306                     |
| wsrep_cluster_size           | 1                                    |
| wsrep_cluster_status         | Primary                              |
| wsrep_connected              | ON                                   |
| wsrep_provider_name          | Galera                               |
| wsrep_ready                  | ON                                   |
+------------------------------+--------------------------------------+
ログ確認(一部抜粋)
tail -f /data/mariadb/logs/cluster/mysql.err
140929 18:34:01 [Note] WSREP: Member 0.0 (db01) synced with group.
140929 18:34:01 [Note] WSREP: Shifting JOINED -> SYNCED (TO: 2323)
140929 18:34:01 [Note] WSREP: New cluster view: global state: 79cff355-2da7-11e4-b83d-5eafba047adc:2323, view# 1: Primary, number of nodes: 1, my index: 0, protocol version 2
Version: '5.5.37-MariaDB-wsrep-log'  socket: '/etc/mariadb/cluster/mysql.sock'  port: 3306  MariaDB Server, wsrep_25.10.r3980

Step 6. 2台目(192.168.0.2)、3台目(192.168.0.3)のノードを起動する

2台目(192.168.0.2)

ノードを起動します
/etc/mariadb/cluster/mysql.server start
Starting MySQL..... SUCCESS!
データ確認(一部抜粋)
MariaDB [(none)]> show status like 'wsrep%';
+------------------------------+-----------------------------------------+
| Variable_name                | Value                                   |
+------------------------------+-----------------------------------------+
| wsrep_local_state_uuid       | 79cff355-2da7-11e4-b83d-5eafba047adc    |
| wsrep_last_committed         | 2323                                    |
| wsrep_local_state_comment    | Synced                                  |
| wsrep_incoming_addresses     | 192.168.0.2:3306,192.168.0.1:3306       |
| wsrep_cluster_size           | 2                                       |
| wsrep_cluster_status         | Primary                                 |
| wsrep_connected              | ON                                      |
| wsrep_provider_name          | Galera                                  |
| wsrep_ready                  | ON                                      |
+------------------------------+-----------------------------------------+
ログ確認(一部抜粋)
tail -f /data/mariadb/logs/cluster/mysql.err
140930 10:36:23 [Note] WSREP: New cluster view: global state: 79cff355-2da7-11e4-b83d-5eafba047adc:2323, view# 2: Primary, number of nodes: 2, my index: 1, protocol version 2
140930 10:36:23 [Note] WSREP: Assign initial position for certification: 2323, protocol version: 3
140930 10:36:23 [Note] WSREP: Member 0.0 (db02) synced with group.

3台目(192.168.0.3)

ノードを起動します
/etc/mariadb/cluster/mysql.server start
Starting MySQL.......SST in progress, setting sleep higher........................... SUCCESS!
データ確認(一部抜粋)
MariaDB [(none)]> show status like 'wsrep%';
+------------------------------+-------------------------------------------------------------+
| Variable_name                | Value                                                       |
+------------------------------+-------------------------------------------------------------+
| wsrep_local_state_uuid       | 79cff355-2da7-11e4-b83d-5eafba047adc                        |
| wsrep_protocol_version       | 5                                                           |
| wsrep_last_committed         | 2323                                                        |
| wsrep_local_state_comment    | Synced                                                      |
| wsrep_incoming_addresses     | 192.168.0.2:3306,192.168.0.3:3306,192.168.0.1:3306          |
| wsrep_cluster_size           | 3                                                           |
| wsrep_cluster_status         | Primary                                                     |
| wsrep_connected              | ON                                                          |
| wsrep_provider_name          | Galera                                                      |
| wsrep_ready                  | ON                                                          |
+------------------------------+-------------------------------------------------------------+
ログ確認(一部抜粋)
tail -f /data/mariadb/logs/cluster/mysql.err
【同期処理】
140930 10:53:59 [Note] WSREP: New cluster view: global state: 79cff355-2da7-11e4-b83d-5eafba047adc:2323, view# 3: Primary, number of nodes: 3, my index: 1, protocol version 2
140930 10:54:01 [Note] WSREP: Running: 'wsrep_sst_rsync --role 'joiner' --address '192.168.0.3:3306' 
--auth 'replica:secret_pass' --datadir '/mnt/mariadb/cluster/' 
--defaults-file '/etc/mariadb/cluster/my.cnf' --parent '15128''
140930 10:54:01 [Note] WSREP: Prepared SST request: rsync|192.168.0.3:3306/rsync_sst
140930 10:54:01 [Note] WSREP: Member 1.0 (db03) requested state transfer from '*any*'. Selected 0.0 (db02)(SYNCED) as donor.
140930 10:54:01 [Note] WSREP: Shifting PRIMARY -> JOINER (TO: 2323)
140930 10:58:26 [Note] WSREP: 0.0 (db02): State transfer to 1.0 (db03) complete.
140930 10:58:26 [Note] WSREP: Member 0.0 (db02) synced with group.
WSREP_SST: [INFO] Joiner cleanup. (20140930 10:58:27.679)
WSREP_SST: [INFO] Joiner cleanup done. (20140930 10:58:28.247)
140930 10:58:28 [Note] WSREP: SST complete, seqno: 2323
【障害からデータ復旧】
InnoDB: Log scan progressed past the checkpoint lsn 41824302522
140930 10:58:28  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Restoring possible half-written data pages from the doublewrite
InnoDB: buffer...
InnoDB: Doing recovery: scanned up to log sequence number 41824302692
InnoDB: Last MySQL binlog file position 0 2182, file name ./mysql-bin.000157
140930 10:58:29  InnoDB: Waiting for the background threads to start
140930 10:58:30 [Note] /usr/local/mysql/bin/mysqld: ready for connections.
Version: '5.5.37-MariaDB-wsrep-log'  socket: '/mnt/mariadb/cluster/mysql.sock'  port: 3306  MariaDB Server, wsrep_25.10.r3980
140930 10:58:30 [Note] WSREP: 1.0 (db03): State transfer from 0.0 (db02) complete.
【最終的な同期処理】
140930 10:58:30 [Note] WSREP: Shifting JOINER -> JOINED (TO: 2323)
140930 10:58:30 [Note] WSREP: Member 1.0 (db03) synced with group.
140930 10:58:30 [Note] WSREP: Shifting JOINED -> SYNCED (TO: 2323)
140930 10:58:30 [Note] WSREP: Synchronized with group, ready for connections

Step 7. 最終的な確認

各サーバーに検証のコマンド(総件数をcountなど)を実行して、各サーバーの検索結果は同じであればOKです。
当ブログは、test_clusterというデータベースでクラスタが復旧されたかどうかを確認します。
【192.168.0.1】でデータを更新します
MariaDB [test_cluster]> select id, asp_name from asps where id = 1;
+----+----------+
| id | asp_name |
+----+----------+
|  1 | test     |
+----+----------+
1 row in set (0.00 sec)

MariaDB [test_cluster]> update asps set asp_name = 'test_sync' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

MariaDB [test_cluster]> update asps set asp_name = 'test_sync' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

MariaDB [test_cluster]> select id, asp_name from asps where id = 1;
+----+-----------+
| id | asp_name  |
+----+-----------+
|  1 | test_sync |
+----+-----------+
1 row in set (0.00 sec)
【192.168.0.2】と【192.168.0.3】で検索してみます。結果は以下通りであればOKです。
MariaDB [test_cluster]> select id, asp_name from asps where id = 1;
+----+-----------+
| id | asp_name  |
+----+-----------+
|  1 | test_sync |
+----+-----------+
1 row in set (0.00 sec)
ここまで来ればMariaDB Galera Clusterを障害から復旧する作業が完了です! 全てのノードが同期されているはずです。
すぐにデータベース全体のバックアップを行って下さい。

おわりに

今回は、MariaDB Galera Clusterの障害からの復旧の方法について解説しました。
完全同期型であるため、すべてのノードがアクティブかつマスターとなりますが、
クラスタを復旧するときに起動するノードの順番が大切ですね。

次世代システム研究室では、データベースアーキテクトを募集しています。大規模データを取り扱うサービスの開発経験者の方、経験は無いけれど、ぜひやってみたいという意欲のある方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。

皆様からのたくさんのご応募、お待ちしてます。

参考リンク