MySQL Clusterのバックアップ/リストアの具体例

2015年9月9日(水)
山﨑 由章

本連載では、実際に「MySQL Cluster」を利用するためのチュートリアルとなるように、その特徴と基本的なアーキテクチャからインストール方法、基本的な操作などをコマンド付きで解説していきます。第5回の今回は、MySQL Clusterのバックアップ/リストアの具体例について解説します。

前提となる環境

記事中のコマンド例は、第2回でインストールした環境を前提としています(追加設定として、mysqlユーザーの環境変数"PATH"に"/home/mysql/mysqlc/bin"も追加した状態)。

第4回で解説した“バックアップ、リストア関連のパラメータ”は明示的に設定していませんので、全てデフォルト設定となっています。今回のチュートリアルでバックアップが格納されるディレクトリはBackupDataDirのデフォルト値である“FileSystemPath/BACKUP”です。FileSystemPathのデフォルト値はDataDirであるためDataDir配下に「BACKUP」というサブディレクトリが作成され、その中にバックアップが格納されます。

今回はチュートリアルが目的であるためこのような設定にしていますが、本番環境ではI/Oの負荷分散のためやバックアップの安全性を高めるために、FileSystemPathとは異なるディスク上のパスを指定することが望ましいです。また、その他のバックアップ、リストア関連のパラメータも必要に応じてチューニングしてください。

サンプルデータベースの作成

バックアップ/リストア後にデータが復旧されていることを確認するために、事前にサンプルデータベースを作成しておきます。サンプルデータベースは、MySQL Developer ZoneMySQL Documentation: Other MySQL Documentationから、通常のMySQL Server用(InnoDB用)のサンプルデータベース作成スクリプトがダウンロードできるので、こちらをMySQL Cluster用に修正して利用します。

MySQL Documentation: Other MySQL Documentationにアクセスし、“Example Databases”の“world database(InnoDB version,)”をダウンロードします(図1)。

サンプルデータベースのダウンロード

図1:サンプルデータベースのダウンロード

ダウンロードしたファイル(gzipとzipどちらでも可)を展開すると、「world_innodb.sql」というSQLスクリプトファイルが入手できます。このSQLスクリプトを実行することでMySQLの研修や認定試験の問題などで利用されている「world」というサンプルデータベースを作成できますが、このSQLスクリプトはInnoDB用です。そのため、テキストエディタ等で開いて以下の通り修正します。

【修正内容】

CREATE TABLE文中のストレージエンジンの指定をInnoDBからndbclusterに修正(リスト1およびリスト2参照)

リスト1:修正前のworld_innodb.sql(Cityテーブル部分のみ抜粋)

CREATE TABLE `City` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`),
  CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `Country` (`Code`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;

リスト2:修正後のworld_innodb.sql(Cityテーブル部分のみ抜粋)

CREATE TABLE `City` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`),
  CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `Country` (`Code`)
) ENGINE=ndbcluster AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;  /* ENGINE=ndbclusterに変更 */

world_innodb.sql中にはCREATE TABLE文が3つありますので、3ヵ所とも同様に修正します(※“ENGINE=ndbcluster”は“ENGINE=ndb”と指定しても同じ意味)。

そして、以下の手順でworldという名前のデータベースを作成し、修正したSQLスクリプトを実行してサンプルデータベースを作成します(リスト3)。

リスト3:サンプルデータベースの作成

$ mysql -u root -h 127.0.0.1
mysql> create database world;
Query OK, 1 row affected (0.05 sec)
mysql> exit
Bye
$ mysql -u root -h 127.0.0.1 world < world_innodb.sql
$
$ #作成されたサンプルデータベースを確認
$ mysql -u root -h 127.0.0.1
mysql> use world;
mysql> show tables;
+-----------------+
| Tables_in_world |
+-----------------+
| City            |
| Country         |
| CountryLanguage |
+-----------------+
3 rows in set (0.00 sec)

mysql> show create table City\G
*************************** 1. row ***************************
       Table: City
Create Table: CREATE TABLE `City` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`),
  CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `Country` (`Code`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=ndbcluster AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> select * from City limit 5;
+------+-----------------+-------------+-------------+------------+
| ID   | Name            | CountryCode | District    | Population |
+------+-----------------+-------------+-------------+------------+
| 2519 | Nezahualcoyotl  | MEX         | Mexico      |    1224924 |
| 1101 | Akola           | IND         | Maharashtra |     328034 |
| 1726 | Ebina           | JPN         | Kanagawa    |     115571 |
|  612 | Port Said       | EGY         | Port Said   |     469533 |
| 1703 | Abiko           | JPN         | Chiba       |     126670 |
+------+-----------------+-------------+-------------+------------+
5 rows in set (0.03 sec)

オンラインバックアップの取得

サンプルデータベースが作成できたので、実際にオンラインバックアップを取得してみましょう。オンラインバックアップは、第4回で解説したように管理ノードから「START BACKUP」コマンドを実行することで取得できます。リスト4では、オンラインバックアップを取得後、取得されたバックアップファイルを確認しています。

リスト4:オンラインバックアップ取得例

$ ndb_mgm -e "START BACKUP"
Connected to Management Server at: localhost:1186
Waiting for completed, this may take several minutes
Node 2: Backup 1 started from node 1
Node 2: Backup 1 started from node 1 completed
 StartGCP: 5265 StopGCP: 5268
 #Records: 7373 #LogRecords: 0
 Data: 498516 bytes Log: 0 bytes
$
$ #取得されたバックアップファイルの確認
$ pwd
/home/mysql/mysqlc/data
$
$ #データノード1上のバックアップファイルの確認(ノードIDは2)
$ ls data1
BACKUP  ndb_2.pid  ndb_2_fs  ndb_2_out.log
$ ls data1/BACKUP
BACKUP-1
$ ls data1/BACKUP/BACKUP-1
BACKUP-1-0.2.Data  BACKUP-1.2.ctl  BACKUP-1.2.log
$
$ #データノード2上のバックアップファイルの確認(ノードIDは3)
$ ls data2
BACKUP  ndb_3.pid  ndb_3_fs  ndb_3_out.log
$ ls data2/BACKUP
BACKUP-1
$ ls data2/BACKUP/BACKUP-1
BACKUP-1-0.3.Data  BACKUP-1.3.ctl  BACKUP-1.3.log

START BACKUPコマンドを再度実行した場合は、バックアップIDが増加して2になります。そのため、BACKUPサブディレクトリ配下に「BACKUP-2」というディレクトリが作成され、バックアップが取得されます。バックアップファイルのファイル名の命名規則については、第4回の表1を参照してください。

また、START BACKUPコマンドには以下の2つのオプションがあります。

  • wait_option:START BACKUPコマンドを実行後、管理クライアントに制御を返すタイミングを指定できる
  • snapshot_option:バックアップを開始した時のクラスタの状態をバックアップするか、バックアップが終了した時のクラスタの状態をバックアップするかを指定できる

デフォルトでは、バックアップ完了後に管理クライアントに制御が返り、バックアップが終了した時のクラスタの状態をバックアップします。オプションの詳細については、こちらのマニュアルを参照してください。

リストアの実行

リストア実行時の考慮事項

リストアを実行する時は、「ndb_restore」という専用コマンドを使用します。第4回で解説したように、バックアップファイルを何処かのサーバ1台に集約し、そのサーバからndb_restoreコマンドを実行します。

ndb_restoreは「APIノード」というMySQL Clusterを構成するノードの1つして動作するため、接続時にノードIDを必要とします。しかし、通常はndb_restore用のノードIDを追加するためにconfig.iniを修正する必要はありません。なぜなら、リストア作業中にSQLノードを停止しておけば、ndb_restoreはSQLノードが使用する予定だったノードIDで接続できるためです(実はSQLノードはAPIノードの1つとして扱われているため、このような動作が可能)。

リストア作業時は、事前に全データノードをイニシャルリスタートし、データファイルを初期化しておきます。一旦全データノードが停止した状態にし、その後それぞれのデータノードをイニシャルリスタートします。また、「リストア作業中にアプリケーションからユーザーが接続してしまう」というトラブルを防ぐためにも、シングルユーザーモードにしてからリストア作業を行う方が安全です。

リストアの実行例

リスト5~リスト9は、リストアの実行例です。先ほど取得したバックアップファイルを別ディレクトリに移して集約した後で、データノードの障害を想定しndbmtdプロセスをkillしています。その後、全データノードをイニシャルリスタートで起動してデータファイルを初期化し、シングルユーザーモードにした後でndb_restoreを実行してバックアップをリストアしています。

ndb_restoreの各オプションの意味は、表1を参照してください。各オプションには短縮系も用意されているため、リスト8では短縮形を用いてコマンドを実行しています。表1に掲載されていないオプションや各オプションのデフォルト値等の詳細は、以下のマニュアルを参照してください。

18.4.20. ndb_restore — MySQL Cluster バックアップのリストア
http://dev.mysql.com/doc/refman/5.6/ja/mysql-cluster-programs-ndb-restore.html

表1:ndb_restoreのオプション

短縮形 オプション名 説明
-c --connectstring 接続文字列
-n --nodeid バックアップを生成したデータノードのノードID
-b --backupid バックアップID
-r --restore_data データのリストアを指示
-m --restore_meta メタデータ(テーブル定義)のリストアを指示
-e --restore_epoch Epochのリストアを指示
  --no-binlog リストア作業中のバイナリログ出力停止を指示

リスト5ではバックアップファイルを集約していますが、この時にバックアップファイルのファイル名を変更してはいけません。ndb_restoreはファイル名によってバックアップファイルを識別しているためです。バックアップファイルを別サーバに集約して管理する際などに、ファイル名を変更しないよう注意してください。

リスト5:バックアップデータの確認とバックアップファイルの集約

$ #バックアップ取得時点のCityテーブルの行数を確認(4079行)
$ mysql -u root -h 127.0.0.1 -e "select count(*) from world.City;"
+----------+
| count(*) |
+----------+
|     4079 |
+----------+
$
$ #バックアップファイルを集約するディレクトリを作成し、各データノードで取得したバックアップファイルをディレクトリごと移動(ディレクトリ名は変更しても、ファイル名は変更しない)
$ pwd
/home/mysql/mysqlc/data
$ mkdir backup
$ ls ./data1/BACKUP/BACKUP-1
BACKUP-1-0.2.Data  BACKUP-1.2.ctl  BACKUP-1.2.log
$ mv ./data1/BACKUP/BACKUP-1 ./backup/2-BACKUP-1
$ ls ./data2/BACKUP/BACKUP-1
BACKUP-1-0.3.Data  BACKUP-1.3.ctl  BACKUP-1.3.log
$ mv ./data2/BACKUP/BACKUP-1 ./backup/3-BACKUP-1
$
$ #集約したバックアップファイルの確認
$ ls ./backup
2-BACKUP-1  3-BACKUP-1
$ ls ./backup/2-BACKUP-1/
BACKUP-1-0.2.Data  BACKUP-1.2.ctl  BACKUP-1.2.log
$ ls ./backup/3-BACKUP-1/
BACKUP-1-0.3.Data  BACKUP-1.3.ctl  BACKUP-1.3.log

リスト6では、データノードの障害を想定しndbmtdプロセスをkillしています。その後、ndbmtdプロセスが1つも起動していないことを確認しています。

リスト6:データノードの障害を想定しndbmtdプロセスをkill

$ #データノードのプロセスをkill
$ ps -ef | grep ndbmtd
mysql      339 32161  0 14:57 pts/1    00:00:00 grep ndbmtd
mysql    32256     1  0 12:21 ?        00:00:02 ndbmtd -c localhost:1186
mysql    32257 32256  3 12:21 ?        00:05:59 ndbmtd -c localhost:1186
mysql    32318     1  0 12:24 ?        00:00:02 ndbmtd -c localhost:1186
mysql    32319 32318  3 12:24 ?        00:05:36 ndbmtd -c localhost:1186
$ kill 32319 32257
$ ps -ef | grep ndbmtd
mysql      345 32161  0 14:58 pts/1    00:00:00 grep ndbmtd

リスト7では、全データノードをイニシャルリスタートで起動してデータファイルを初期化しています。その後、リストア作業中にアプリケーションユーザーが接続できないようにSQLノードを停止し、シングルユーザーモードへ移行しています。

リスト7:データノードのイニシャルリスタートとシングルユーザーモードへの移行

$ #データノードをイニシャルリスタート
$ ndbmtd -c localhost:1186 --initial
$ ndbmtd -c localhost:1186 --initial
$
$ #CityテーブルにSELECT実行(データファイルが初期化されているため、Cityテーブルは存在しない)
$ mysql -u root -h 127.0.0.1 -e "select count(*) from world.City;"
ERROR 1146 (42S02) at line 1: Table 'world.City' doesn't exist
$
$ #全SQLノードを停止
$ mysqladmin -u root -h 127.0.0.1 shutdown
$ mysqladmin -u root -h 127.0.0.1 -P 3307 shutdown
$
$ #クラスタの状態確認
$ ndb_mgm -e SHOW
Connected to Management Server at: localhost:1186
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=2    @127.0.0.1  (mysql-5.6.24 ndb-7.4.6, Nodegroup: 0, *)
id=3    @127.0.0.1  (mysql-5.6.24 ndb-7.4.6, Nodegroup: 0)

[ndb_mgmd(MGM)] 1 node(s)
id=1    @127.0.0.1  (mysql-5.6.24 ndb-7.4.6)

[mysqld(API)]   2 node(s)
id=4 (not connected, accepting connect from any host)
id=5 (not connected, accepting connect from any host)

$
$ #シングルユーザーモードに移行(普段SQLノードで使用しているノードIDを、1つだけ指定する)
$ ndb_mgm -e "ENTER SINGLE USER MODE 4"
Connected to Management Server at: localhost:1186
Single user mode entered
Access is granted for API node 4 only.

リスト8では、ndb_restoreを実行してバックアップをリストアしています。各データノードで取得したバックアップファイル毎にコマンドを実行する必要があるため、今回の例では2回ndb_restoreを実行します(データノードが4ノード構成であれば、4回ndb_restoreを実行)。

メタデータ(テーブル定義)のリストアは、最初にndb_restoreを実行する時だけ必要なため、2回目以降は不要です。また、Epochのリストアは1回だけで構いません。リスト8では最後にndb_restoreを実行する時だけEpochをリストアしています。Epochをリストアすると、バックアップ取得時点のEpochの情報がmysql.ndb_apply_statusテーブルに格納されます。Epochの情報は、MySQL Clusterでレプリケーションを構成する時や、バックアップリストア後にバイナリログを使用してロールフォワードリカバリを行う時などに利用します。MySQL Clusterのバイナリログの扱いは、通常のMySQL Serverと異なる点があるため、今後の連載で解説予定です。

今回の環境ではバイナリログを出力していないため、--no-binlogオプションを指定しても影響がありません。しかし、バイナリログを出力している環境においては、このオプションを指定した方がリストアは早くなります。

リスト8:ndb_restoreを実行してバックアップをリストア

$ #ndb_restoreでリストア開始(データノード1で取得したバックアップをリストア)
$ ndb_restore -c localhost:1186 -n 2 -b 1 -r -m --no-binlog ./backup/2-BACKUP-1
Nodeid = 2
Backup Id = 1
backup path = ./backup/2-BACKUP-1
Opening file './backup/2-BACKUP-1/BACKUP-1.2.ctl'
File size 31596 bytes
Backup version in files: ndb-6.3.11 ndb version: mysql-5.6.24 ndb-7.4.6
Stop GCP of Backup: 5267
Connected to ndb!!
Successfully restored table `world/def/CountryLanguage`
<中略>
_____________________________________________________
Processing data in table: world/def/Country(15) fragment 0
Opening file './backup/2-BACKUP-1/BACKUP-1.2.log'
File size 52 bytes
Restored 2697 tuples and 0 log entries

NDBT_ProgramExit: 0 - OK

$
$ #リストア途中の状態を確認するために、CityテーブルとEpochの情報を確認
$ # ・Cityテーブルには約半分のデータが入っている
$ # ・Epochの情報はまだリストアしていないため、mysql.ndb_apply_statusテーブルにはデータが入っていない
$ #(確認のために実施している手順であるため、通常運用時はこの手順は不要)
$ mysqld --defaults-file=/home/mysql/mysqlc/my1.cnf &
$ mysql -u root -h 127.0.0.1 -e "SELECT COUNT(*) FROM world.City";
+----------+
| COUNT(*) |
+----------+
|     2084 |
+----------+
$ mysql -u root -h 127.0.0.1 -e "SELECT COUNT(*) FROM mysql.ndb_apply_status;";
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
$ mysqladmin -u root -h 127.0.0.1 shutdown
$
$ #ndb_restoreでリストア開始(データノード2で取得したバックアップをリストア)
$ ndb_restore -c localhost:1186 -n 3 -b 1 -r -e --no-binlog ./backup/3-BACKUP-1
Nodeid = 3
Backup Id = 1
backup path = ./backup/3-BACKUP-1
Opening file './backup/3-BACKUP-1/BACKUP-1.3.ctl'
File size 31596 bytes
Backup version in files: ndb-6.3.11 ndb version: mysql-5.6.24 ndb-7.4.6
Stop GCP of Backup: 5267
Connected to ndb!!
Opening file './backup/3-BACKUP-1/BACKUP-1-0.3.Data'
<中略>
_____________________________________________________
Processing data in table: world/def/Country(15) fragment 1
Opening file './backup/3-BACKUP-1/BACKUP-1.3.log'
File size 52 bytes
Restored 2605 tuples and 0 log entries

NDBT_ProgramExit: 0 - OK

リスト9では、シングルユーザーモードを終了し、SQLノードを起動してリストアされたデータを確認しています。データがリストアされたことをCityテーブルの件数のみで確認していますが、もちろん実データや他のテーブルも正しくリストアされています。実際に試す際には、他のテーブルや実データがリストアされていることも確認してみてください。

リスト9:シングルユーザーモードを終了しSQLノードを起動してデータを確認

$ #シングルユーザーモードを終了し、SQLノードを起動
$ ndb_mgm -e "EXIT SINGLE USER MODE"
Connected to Management Server at: localhost:1186
Exiting single user mode in progress.
Use ALL STATUS or SHOW to see when single user mode has been exited.
$ mysqld --defaults-file=/home/mysql/mysqlc/my1.cnf &
$ mysqld --defaults-file=/home/mysql/mysqlc/my2.cnf &
$
$ #リストアされていることを確認するために、CityテーブルをSELECT
$ mysql -u root -h 127.0.0.1 -e "SELECT COUNT(*) FROM world.City;";
+----------+
| COUNT(*) |
+----------+
|     4079 |
+----------+
$ #Epochの情報もリストアされていることを確認
$ mysql -u root -h 127.0.0.1 -e "SELECT COUNT(*) FROM mysql.ndb_apply_status;";
+----------+
| COUNT(*) |
+----------+
|        1 |
+----------+
$ mysql -u root -h 127.0.0.1 -e "SELECT * FROM mysql.ndb_apply_status;";
+-----------+----------------+----------+-----------+---------+
| server_id | epoch          | log_name | start_pos | end_pos |
+-----------+----------------+----------+-----------+---------+
|         0 | 22630182682623 |          |         0 |       0 |
+-----------+----------------+----------+-----------+---------+

おわりに

今回は、MySQL Clusterのバックアップ/リストアの具体例について解説しました。第6回では、MySQL Clusterのサイジングについて解説する予定です。

※本稿において示されている見解は、私自身の見解であって、私の所属するオラクルの見解を必ずしも反映したものではありません。

日本オラクル株式会社

MySQLのセールスコンサルタント。元々はOracleデータベースのコンサルティング、サポート等に従事していたが、オープンソースとフリーソフトウェア(自由なソフトウェア)の世界に興味を持ち、MySQLの仕事を始める。趣味は旅行と美味しいものを食べること。

連載バックナンバー

データベース技術解説

MySQL Clusterにおけるチューニングの基礎

2015/12/10
第9回の今回は、MySQL Clusterにおけるチューニングの基礎について解説します。
データベース技術解説

MySQL Clusterにおけるレプリケーション環境構築例

2015/11/19
MySQL Clusterにおけるレプリケーション環境構築の具体例について解説します。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています