CUBE SUGAR CONTAINER

技術系のこと書きます。

MariaDB のデータを mysqldump でバックアップ・リストアする

MySQL (MariaDB) のデータをバックアップ・リストアする方法には色々なやり方があるみたい。 今回は、その中でも最もオーソドックスな mysqldump を使う方法を試してみる。 また、mysqldump はその時点でのデータベースの内容を全て書き出すフルバックアップなので、コマンドを実行した後に行われた更新内容についてはリストアすることができない。 そのため、フルバックアップ後の更新内容については MySQL (MariaDB) からリアルタイムに出力されるバイナリログを差分バックアップとして残しておき、障害直前のデータまで復旧を行うロールフォワードリカバリについても試しておく。

今回の検証環境には CentOS7 を使った。 また、リストア元とリストア先でふたつの仮想マシンを用意しておくと良い。

$ cat /etc/redhat-release 
CentOS Linux release 7.1.1503 (Core) 
$ uname -r
3.10.0-229.11.1.el7.x86_64

バックアップする MariaDB を準備する

まずは MariaDB をインストールする。

$ sudo yum -y install mariadb-server

MariaDB の設定ファイルを用意する。 ここで重要なのは log-bin の設定を入れることでバイナリログを残すようにしておくこと。 mysqldump はデータベースの中身を全て書き出すフルバックアップになるから、それだけを使うと途中までのデータしかリストアできない。

$ cat << EOF | sudo tee /etc/my.cnf.d/server.cnf > /dev/null
[mariadb]
binlog_format = row
log-bin = mysql-bin
log-error = error.log
slow_query_log_file   = slow-queries.log
character-set-server = utf8mb4
default_storage_engine = InnoDB
binlog-ignore-db = mysql
EOF

設定を入れ終わったら MariaDB のサービスを開始する。

$ sudo systemctl start mariadb
$ sudo systemctl enable mariadb

テスト用のデータベースとテーブルを作って、その中に二つほど行を挿入しておく。

$ mysql -u root -e "create database sample"
$ mysql -u root -D sample -e "create table users (id Integer primary key auto_increment, name Text not null)"
$ mysql -u root -D sample -e "insert into users (name) values ('foo')"
$ mysql -u root -D sample -e "insert into users (name) values ('bar')"

mysqldump でフルバックアップを取得する

それでは mysqldump コマンドを使ってデータのフルバックアップを取得する。 バックアップ対象のデータベースのストレージエンジンが InnoDB 互換であれば --single-transaction オプションを付けることで一貫性の取れたデータがバックアップできる。 --master-data=2 はロールフォワードリカバリにどのバイナリログを使えばいいかをダンプしたファイルの中に書き込むためにつける。 --flush-logs はログの内容をフラッシュした上でバイナリログのファイルをローテーションしてくれる。 ちなみに、検証環境に Vagrant を使ってリストア元とリストア先でふたつの仮想マシンを作成しているので、出力先には共有ディレクトリを指定している。

$ mysqldump --user=root --single-transaction --master-data=2 --flush-logs --database sample > /vagrant/dump.sql

出力される内容は単なるテキストファイルになっていて、中身は SQL 文がずらずらと書かれている。 つまり、まっさらな状態から現在のデータベースを作るのに必要な全ての SQL 文が入ったファイルということだ。

$ file /vagrant/dump.sql 
/vagrant/dump.sql: ASCII text

フルバックアップからデータをリストアする

ここからは取得したデータを元にデータをリストアする作業に入る。 リストア先の環境には先ほどとは別の仮想マシンを使うのがおすすめ。 あるいは、単純に作成したデータベースを削除するだけでも良いのかな。

$ mysqladmin -u root drop sample
Dropping the database is potentially a very bad thing to do.
Any data stored in the database will be destroyed.

Do you really want to drop the 'sample' database [y/N] y
Database "sample" dropped

mysqldump で出力されるのは SQL 文の書かれたテキストファイルなので、そのデータを使ってリストアするには mysql コマンド経由で入力してやるだけでいい。

$ mysql -u root < /vagrant/dump.sql

リストア後のデータベースを確認すると、ちゃんと中身が入っている。

$ mysql -u root -e "show databases"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sample             |
| test               |
+--------------------+
$ mysql -u root -D sample -e "select * from users"
+----+------+
| id | name |
+----+------+
|  1 | foo  |
|  2 | bar  |
+----+------+

ロールフォワードリカバリを試す

ここからはフルバックアップ後に更新された内容を、バイナリログを元にリストアするロールフォワードリカバリを試してみる。 動作を確認するために、リストア元のデータベースに新たに行を追加しておく。

$ mysql -u root -D sample -e "insert into users (name) values ('baz')"

使用するバイナリログを確認する

先ほどフルバックアップしたファイルの内容をみると、ロールフォワードリカバリには 'mysql-bin.000004' というファイルを使えば良いことがわかる。

$ cat /vagrant/dump.sql | grep -i change
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=245;

バイナリログは /var/lib/mysql にデフォルトで保存されるので、それをリストア先の仮想マシンが見える場所にコピーしておく。

$ sudo cp /var/lib/mysql/mysql-bin.000004 /vagrant

ロールフォワードリカバリする

ここからは先はリストア先の仮想マシンで作業する。 バイナリログは mysqlbinlog コマンドを使って SQL 文に変換できる。 変換したら後はフルバックアップのデータと同様に mysql コマンド経由で入力してやればいい。

$ mysqlbinlog /vagrant/mysql-bin.000004 | mysql -u root

ロールフォワードリカバリ後の中身を確認すると、ちゃんとフルバックアップ後の変更内容が反映されていることがわかる。

$ mysql -u root -D sample -e "select * from users"
+----+------+
| id | name |
+----+------+
|  1 | foo  |
|  2 | bar  |
|  3 | baz  |
+----+------+

ばっちり。

まとめ

今回は mysqldump を使ったバックアップ・リストアを CentOS7/MariaDB の環境で試してみた。 また、mysqldump で取れるのはフルバックアップなので、バイナリログの差分バックアップを使ったロールフォワードリカバリについても試した。 前述した通り MySQL (MariaDB) のバックアップ方法は色々とあるようだけど、mysqldump コマンドを使ったやり方はシンプルで導入しやすいものだと思う。