はじめに

こんにちは、インフラソリューション部の Kzzz です。普段は Terraform で AWS を扱い社内インフラの運用・保守・改善をしています。

近年、コンプライアンスなどの対応のため、終了したサービスのデータベースを一定の期間保持しておかなければならないことが多くなってきました。

今回はそのような場合に、常に起動しておく必要はないが、たま〜に起動して使用できるようにデータベースをバックアップ・リストアする方法を AWS ドキュメントのAmazon Aurora MySQL DB クラスターへのデータの移行に記載されている3種類の方法を用いて試してみます!

試してみる移行方法

  • Percona XtraBackup を使用したバックアップとリストア
  • mysqldump を使用したバックアップとリストア
  • テキストファイルを使用したバックアップとリストア

前提

目的

Amazon EC2 やオンプレなどの Amazon RDS 以外の環境で運用されていた 100 GB の MySQL データベースをアーカイブ化して保持したのち、Amazon Aurora MySQL にリストアして、ユーザーデータなどへアクセスできるようにします。

検証環境のバージョン

今回の検証では、移行元データベースを手元の MacBook の Docker 内で作成したデータベースを使用します。

オンプレ環境

PC : MacBook Pro 14inch, 2023, 16GB
Docker : 24.0.6
MySQL : 8.0.28
Percona XtraBackup : 8.0.28-21

Docker Desktop の設定

Docker Desktop : v4.25.0
CPU limit : 10
Memory limit : 8GB
Swap : 2GB

リストアに使用する EC2 インスタンス

AMI : Amazon Linux 2
インスタンスタイプ : t2.small
MySQL : 8.0.28
Percona XtraBackup : 8.0.28-21

Amazon Aurora MySQL

エンジンバージョン : 8.0.mysql_aurora.3.04.1
インスタンスクラス : db.t3.medium

準備

データベース移行検証に使うために mysql_random_data_load というランダムデータ生成ツールを使用して約 100 GB のデータベースを用意しました。

du -h /var/lib/mysql/
116K    /var/lib/mysql/sys
804K    /var/lib/mysql/#innodb_temp
36K /var/lib/mysql/mysql
1.6M    /var/lib/mysql/performance_schema
100G    /var/lib/mysql/test_db
101G    /var/lib/mysql/

Percona XtraBackup を使用したバックアップとリストア

まず始めは、AWS ドキュメントの中で、mysqldump を使用した方法よりもかなり高速になる場合があると記載されている移行方法である Percona XtraBackup を使用した方法を試していきます。

手順

Percona XtraBackup を使用した方法の手順は、このような流れで行っていきます。
  1. Percona XtraBackup でバックアップの作成
  2. バックアップを Amazon S3 にアップロード
  3. Amazon RDS からバックアップをリストア
作業はこちらの資料を参考に行っていきます。 それでは、やっていきましょう!

バックアップ

Percona XtraBackup のインストール

今回の移行環境が MySQL 8.0.28 なので Percona XtraBackup 8.0.28 をインストールします。自身の環境に合ったバージョンは Percona のダウンロードサイトで確認が必要です。

wget https://downloads.percona.com/downloads/Percona-XtraBackup-8.0/Percona-XtraBackup-8.0.28-21/binary/debian/buster/x86_64/percona-xtrabackup-80_8.0.28-21-1.buster_amd64.deb
dpkg -i percona-xtrabackup-80_8.0.28-21-1.buster_amd64.deb

インストールの確認をします。

xtrabackup --version
xtrabackup version 8.0.28-21 based on MySQL server 8.0.28 Linux (x86_64) (revision id: 78878e9b608)

バックアップファイルの作成

バックアップファイルは 公式ドキュメントに沿って 5 GB ずつに分割して作成していきます。今回は Amazon S3 へのアップロードに AWS CLI を使用するので、分割しなくても問題ありません。
また Percona XtraBackup のバックアップファイルの圧縮形式は Gzip、tar、xbstream と複数ありますが MySQL 8.0 では xbstream のみしか対応していないので注意が必要です。
圧縮用に Percona xbstream のみをサポートします。

Percona XtraBackup と Amazon S3 を使用した MySQL からの物理移行
Percona XtraBackup で完全バックアップを作成します。

time xtrabackup --backup --user=<usename> --password=<password> --compress --compress-threads=4 --target-dir=/var/backups/xtrabackup --stream=xbstream | split -d --additional-suffix=.xbstream --bytes=5GB - /var/backups/xtrabackup/backup

約 17 分で完了しました。

real 17m6.070s
user 26m36.409s
sys 1m55.762s

バックアップファイルは 10 個に分割され、圧縮されてファイルサイズが半分以下になりました。

ls /var/backups/xtrabackup
backup00.xbstream  backup01.xbstream  backup02.xbstream  backup03.xbstream  backup04.xbstream  backup05.xbstream  backup06.xbstream  backup07.xbstream backup08.xbstream  backup09.xbstream
 
du -h /var/backups/xtrabackup
46G /var/backups/xtrabackup

Amazon S3 バケットへバックアップファイルをアップロード

Amazon S3 のコンソールでバックアップファイルをアップロードするバケットを作成して、AWS CLI でアップロードします。 また、S3 バケットのストレージクラスは保持コストとデータ取り出し時間とのバランスのいい Glacier Instant Retrieval を指定していきます。

aws s3 cp /var/backups/xtrabackup/ s3://kzzz-mysql-backup-test/xtrabackup/ --recursive  --storage-class GLACIER_IR

問題なくアップロード完了できれば、バックアップ手順は完了です!

リストア

Amazon RDS で S3 のバックアップファイルからデータベースを復元

RDS > データベース > S3 から復元 で復元するデータベースの設定を行います。
S3 送信先 はバックアップファイルを保存しているバケットとフォルダを指定します。
エンジンのオプション では移行元の環境と互換性のある Aurora MySQL を指定します。今回は MySQL 8.0.28 なので、Aurora MySQL 3.04.1(compatible with MySQL 8.0.28) を選択します。 IAM ロール では 新しいロールの作成 を選択すれば適切な権限が付与されたロールがアタッチされるので新規作成します。
最後に データベースの作成 をクリックして復元(リストア) を開始します! 私の環境では、復元開始からインスタンスが利用可能になるまで約 56 分かかりました。
作成後、ライターインスタンスにログインしデータベースの確認をしてリストア手順は完了です!

条件を変えて復元してみる

先ほどは公式ドキュメントの手順通りにリストアしましたが、条件を色々と変更して復元時間が変わるか試してみました。
条件バックアップ作成時間リストア時間バックアップファイルサイズ
圧縮あり18 分58 分46 GB
圧縮なし18 分58 分100 GB
圧縮あり+5 GB で split17 分56 分46 GB
圧縮なし+5 GB で split18 分55 分100 GB
こちらの条件では、復元にかかる時間に変化はありませんでした。
S3 にアップロードする際の時間と S3 のストレージ料金を少なくするため、基本的にバックアップファイルは圧縮した方が良さそうです。

結果

Percona XtraBackup を使用したバックアップとリストアにかかった時間の平均はこのようになりました。
バックアップ作成時間リストア時間トータル時間
18 分58 分76 分
Percona XtraBackup を使用した方法は、AWS 側でも推奨している移行方法ということもあり、手順が簡略化、リストアの最適化がされており、とてもスムーズに移行ができました!

mysqldump を使用したバックアップとリストア

次に mysqldump を使用した方法を試していきます。こちらの方法では、リストアを実行する環境を自分で用意しなきゃいけないので、手順がやや複雑になります。

手順

mysqldump を使用した方法の手順は、このような流れで行っていきます。
  1. mysqldump コマンドでバックアップを作成
  2. バックアップを Amazon S3 にアップロード
  3. リストア用 EC2 インスタンスを作成
  4. 移行先の Aurora MySQL インスタンスを作成
  5. mysqldump コマンドでリストア
作業はこちらの資料を参考に行っていきます。 リストア用の EC2 インスタンスを中継にしてリストアを行うため、手順が AWS のドキュメントよりも多くなっています。 それでは、やっていきましょう!

バックアップ

バックアップファイルを作成

移行元のオンプレ環境で mysqldump コマンドを使用してバックアップファイルを作成します。バックアップファイルはアップロード時間の短縮とストレージ料金を削減するために pbzip2 で圧縮します。
移行元のデータベースがある環境にログインして mysqldump コマンドを実行します。同時にパイプを利用してバックアップファイルを圧縮していきます。

time mysqldump -u root \
   --databases test_db \
   --single-transaction \
   --order-by-primary \
   --routines=0 \
   --triggers=0 \
   --events=0 \
   -p | pbzip2 -p10 > /var/backups/mysqldump/backup.dump.bz2

バックアップファイルは約 92 分で出力でき、約 18.7 GB に圧縮できました。

real 92m44.723s
user 424m58.538s
sys 7m3.**957s**

Amazon S3 バケットへバックアップファイルをアップロード

AWS CLI でバックアップファイルを Amazon S3 にアップロードします。 S3 バケットのストレージクラスは保持コストとデータ取り出し時間とのバランスのいい Glacier Instant Retrieval を指定します。

aws s3 cp /var/backups/mysqldump/backup.dump.bz2 s3://kzzz-mysql-backup-test/mysqldump/  --storage-class GLACIER_IR

こちらで問題なくアップロード完了できれば、バックアップ手順は完了です!

リストア

リストア用の EC2 インスタンスを作成

Amazon S3 にアップロードしたバックアップファイルをオンプレ環境にダウンロードして RDS へリストアする方法より AWS 内のネットワークで完結させた方がデータ転送料金を削減できるので、リストア用の EC2 インスタンスを作成してリストアをします。
リストア用の EC2 インスタンスの構成は以下のようにしました。
AMIAmazon Linux 2
インスタンスタイプt2.small

移行先の Aurora MySQL インスタンスを作成

次に Amazon RDS で移行元の MySQL のバージョンと互換性がある Aurora MySQL インスタンスを作成します。 Amazon RDS の構成は以下のようにしました。
エンジンバージョン8.0.mysql_aurora.3.04.1
インスタンスクラスdb.t3.medium

mysqldump コマンドでリストア

Aurora MySQL インスタンスが立ち上がったら、リストア用の EC2 インスタンスの環境にログインし、mysqldump コマンドを使用してデータベースを移行します。 移行の際はパイプを使用してバックアップファイルのダウンロード、圧縮ファイルの解凍、mysqldump をまとめて実行します。

time aws s3 cp s3://kzzz-mysql-backup-test/mysqldump/backup.dump.bz2 - \
    | pbzip2 -d \
    | mysql -u <username> -h <RDSのエンドポイント> -p

リストアコマンドの完了には約 344 分かかりました。

real 344m36.031s
user 106m19.297s
sys 4m10.825s

最後に移行先の Aurora MySQL インスタンスにログインして、データベースがリストアできているか確認できれば完了です!

結果

mysqldump コマンドを使用したバックアップとリストアにかかった時間はこのようになりました。オンプレから S3 へのバックアップファイルのアップロード時間はばらつきがあるため省略しています。
バックアップ作成時間リストア時間トータル時間
92 分334 分426 分
mysqldump コマンドを使用した方法では、リストアの際にデータを Aurora MySQL にインポートする処理がボトルネックになっており、リストア時間が伸びてしまいました。

テキストファイル を使用したバックアップとリストア

最後にテキストファイルを使用した方法を試していきます。こちらの方法では、移行先の Aurora MySQL から直接 Amazon S3 のバックアップファイルをインポートするので、Aurora MySQL に適切な権限を設定する手順が必要になります。

手順

  1. SELECT INTO OUTFILE コマンドでテキストファイルを作成
  2. テキストファイルを圧縮
  3. 圧縮したテキストファイルを Amazon S3 にアップロード
  4. 解凍用の EC2 インスタンスを作成
  5. 圧縮したテキストファイルを解凍
  6. 移行先の Aurora MySQL インスタンスを作成
  7. Aurora MySQL の権限設定
  8. Aurora MySQL からバックアップファイルをインポート
作業はこちらの資料を参考に行っていきます。 それでは、やっていきましょう!

バックアップ

移行するテーブルのテキストファイルを作成

テキストファイルを使用する方法では、テーブル単位でテキストファイルを作成する必要があります。
移行元のデータベースにログインし、SELECT INTO OUTFILE コマンドを実行して移行するテーブルのテキストファイルを作成します。

SELECT * FROM test_tb INTO OUTFILE '/var/backups/textfile/backup.txt' FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';

テキストファイルの出力には約 1 時間 27 分かかりました。

Query OK, 187320000 rows affected (1 hour 27 min 45.50 sec)

出力したテキストファイルのサイズは 89 GB でした。

ls -lh backup.txt
-rw-r----- 1 mysql mysql 89G Dec 10 12:21 backup.txt

テキストファイルを pbzip2 で圧縮

他の方法と同様、バックアップファイルはアップロード時間の短縮とストレージ料金を削減するために pbzip2 で圧縮します。

time pbzip2 -p10 backup.txt

バックアップファイルのサイズは約 18.6 GB になり、圧縮には 41 分かかりました。

real    41m33.664s
user    411m36.183s
sys 2m11.885s

テキストファイルを S3 にアップロード

AWS CLI でバックアップファイルを Amazon S3 にアップロードします。
S3 バケットのストレージクラスは保持コストとデータ取り出し時間とのバランスのいい Glacier Instant Retrieval を指定します。

time aws s3 cp /var/backups/textfile/backup.txt.bz2 s3://kzzz-mysql-backup-test/textfile/ --storage-class GLACIER_IR

こちらで問題なくアップロード完了できれば、バックアップ手順は完了です!

リストア

解凍用の EC2 インスタンスを作成

テキストファイルを使用するリストア方法でも mysqldump を使用するリストア方法と同様に、Amazon S3 のデータ転送料金を削減するために解凍用の EC2 インスタンスを作成してバックアップファイルを解凍します。
解凍用の EC2 インスタンスの構成も同様です。
AMIAmazon Linux 2
インスタンスタイプt2.small

Amazon S3 に保存されているバックアップファイルを解凍

mysqldump の方法と違いテキストファイルを使用する方法では、Aurora MySQL インスタンスから直接 Amazon S3 のバックアップファイルをリストアするので、事前に圧縮されているバックアップファイルを解凍する必要があります。
解凍用の EC2 インスタンスにログインし、パイプを使用して Amazon S3 にあるバックアップファイルのダウンロード、解凍、Amazon S3 へのアップロードを一度に実行します。

time sudo aws s3 cp s3://kzzz-mysql-backup-test/textfile/backup.txt.bz2 - | pbzip2 -d | aws s3 cp - s3://kzzz-mysql-backup-test/textfile/backup.txt

real 90m35.299s
user 83m33.712s
sys 6m35.515s

処理が完了するまで約 90 分かかりました。

Amazon RDS で移行先の Aurora MySQL インスタンスを作成

次に Amazon RDS で移行元の MySQL のバージョンと互換性がある Aurora MySQL インスタンスを作成します。


Amazon RDS の構成は以下のようにしました。
エンジンバージョン8.0.mysql_aurora.3.04.1
インスタンスクラスdb.t3.medium

移行に必要なアクセス権限を移行先クラスターに設定

Amazon S3 へアクセスできるように以下の IAM ポリシーを Aurora MySQL DB クラスターにアタッチします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::kzzz-mysql-backup-test",
                "arn:aws:s3:::kzzz-mysql-backup-test/*"
            ]
        }
    ]
}

ポリシーのアタッチは RDS > データベース > Aurora MySQL DB クラスター名 > IAM ロールの管理 からできます。

パラメータグループを作成

続いて、DB クラスターのパラメータグループを作成します。
パラメータグループの詳細 は以下のように設定します。
作成したパラメータグループを編集して aws_default_s3_role の値に先ほど作成した IAM ポリシーの ARN を入力して 変更を保存を選択します。
最後に RDS > データベース > DB クラスターの変更 > 追加設定 > データベースの選択肢 > DB クラスターのパラメータグループ で作成したパラメータグループを DB クラスターにアタッチします。

VPC エンドポイントの作成

今回の環境は DB クラスターが Private サブネット内にあるので、このままでは S3 にアクセスできるよう DB クラスターのアウトバウンド接続を有効にする必要があります。
VPC > エンドポイント > エンドポイントを作成 から S3 へのエンドポイントを作成します。
サービスでは Gateway タイプのものを、VPC では DB クラスターと同じものを選択してください。

Aurora MySQL インスタンスで AWS_LOAD_S3_ACCESS 権限を付与

Aurora MySQL インスタンスにログインしてデータをロードするための権限をユーザに付与するために GRANT コマンドを実行します。
user と domain-or-ip-address は各自設定を変えてください。

GRANT AWS_LOAD_S3_ACCESS TO '`user`'@'`domain-or-ip-address`'

Aurora MySQL インスタンスに移行元のテーブルを作成

LOAD DATA FROM S3 コマンドではテーブル単位でデータをインポートするため、移行元と同じ構成のテーブルを移行先である DB クラスターに作成しておく必要があります。

LOAD DATA FROM S3 コマンドで S3 のテキストファイルからテーブルをインポート

SELECT INTO OUTFILE コマンドでテキストファイルにしたときの形式に合わせてインポートします。

LOAD DATA FROM S3 's3://kzzz-mysql-backup-test/textfile/backup.txt'
    INTO TABLE test_tb
    FIELDS TERMINATED BY ','
    LINES TERMINATED BY '\n';

89 GB のテキストファイルで約 3 時間 27 分かかりました。

Query OK, 187320000 rows affected (3 hours 27 min 54.45 sec)
Records: 187320000  Deleted: 0  Skipped: 0  Warnings: 0

結果

テキストファイルを使用したバックアップとリストアにかかった時間はこのようになりました。オンプレから S3 へのバックアップファイルのアップロード時間はばらつきがあるため省略しています。
バックアップ作成時間
リストア時間トータル時間
87 分(テキストファイル作成時間) + 41 分(圧縮時間)90 分(解凍時間) + 207 分(インポート時間)425 分
テキストファイルを使用した方法では、テーブル単位でしかインポートができない点と AWS コンソール上での操作が多く、バックアップ、リストアの処理以外の作業時間が他の方法よりも多くかかってしまいました。

バックアップファイルの有効期間とストレージコスト

バックアップファイルの有効期間

今回の移行先である Amazon Aurora MySQL v3 はバージョンの種類によって利用可能な期間は変わってきます。
バージョンの種類利用可能期間
Amazon Aurora マイナーバージョンリリースから少なくとも 12 か月間
Amazon Aurora マイナーバージョン(LTS)リリースから少なくとも 3 年間
Amazon Aurora メジャーバージョン少なくとも対応するコミュニティバージョンのコミュニティが終了するまで
AWS で説明されているドキュメント通りであれば、LTS のマイナーバージョンを選択しておくのが無難そうです。(リリース時期は要確認)
またマイナーバージョンに移行元 MySQL のバージョンを合わせるためにアップグレードする際は、MySQL 8.0 → MySQL 5.7 へのダウングレードはできないので注意が必要になります。

バックアップファイルのストレージコスト

Amazon S3 でバックアップファイルを保存しておく場合、別途ストレージコストがかかってきます。

Amazon S3  でのバックアップファイル保持コスト(東京リージョン)

Amazon S3 のストレージクラスごとのストレージコスト、アクセス性能を比較すると以下のようになります。AWS のリージョンは東京リージョンです。
ストレージクラスストレージコスト/月データ取り出しコストアクセス性能の表記
S3 標準0.025USD/GB該当なし低レイテンシー
S3 標準 – 低頻度アクセス0.0138USD/GB0.01USD/GBミリ秒単位
S3 One Zone – 低頻度アクセス0.011USD/GB0.01USD/GBミリ秒単位
S3 Glacier Instant Retrieval0.005USD/GB0.03USD/GBミリ秒単位
S3 Glacier Flexible Retrieval (標準)0.0045USD/GB0.011USD/GB1 分から 12 時間
S3 Glacier Deep Archive (標準)0.002USD/GB0.022USD/GB12 時間以内
※ Amazon S3 からインターネットへのデータ転送送信には更にコストがかかります。
※ こちらは 2024 年 1 月のものになります。最新のコストは AWS ドキュメントの Amazon S3 の料金 ページを確認ください。

バックアップファイル (100 GB) の保持と初回取り出しにかかるコスト比較

100 GB のバックアップファイルを Amazon S3 に保存した期間と1回の取り出しにかかるコストの合計を 6 ヶ月分比較したグラフは以下のようになりました。
また 6 ヶ月移行の一年単位の推移は以下のようになりました。
保持期間(100 GB)
1 month6 month12 month24 month36 month
S3 標準2.38 USD9.28 USD17.56 USD34.12 USD50.68 USD
S3 標準 – 低頻度アクセス2.50 USD15.00 USD30.00 USD60.00 USD90.00 USD
S3 One Zone – 低頻度アクセス2.10 USD7.60 USD14.20 USD27.40 USD40.60 USD
S3 Glacier Instant Retrieval3.50 USD6.00 USD9.00 USD15.00 USD21.00 USD
S3 Glacier Flexible Retrieval (標準)1.55 USD3.80 USD6.50 USD11.90 USD17.30 USD
S3 Glacier Deep Archive (標準)2.40 USD3.40 USD4.60 USD7.00 USD9.40 USD
これらの結果から、アクセス性能を必要とせずコスト削減を重要視するなら S3 Glacier Deep Archive、ミリ単位のアクセス性能が必要な場合は S3 Glacier Instant Retrieval がバックアップファイルの保存先としてバランスが良さそうです。

まとめ

今回色々な方法でバックアップ、リストアを行いこのような結果になりました。

バックアップとリストアにかかったトータル時間

移行方法バックアップ作成時間リストア時間トータル時間年間のストレージコスト+1回リストア
Percona XtraBackup を使用した方法
18 分 (46GB)57 分75 分 + Amazon S3 へのアップロード時間4.14 USD
mysqldump を使用した方法92 分 (18.7 GB)344 分436 分 + Amazon S3 へのアップロード時間1.68 USD
テキストファイルを使用した方法128 分 (18.6 GB)297 分425 分 + Amazon S3 へのアップロード時間1.67 USD
よって今回の環境では、Percona XtraBackup を使用した方法が最適解と言える結果となりました。

感想

検証した結果、Percona XtraBackup が復元時間が短くコンソール上での作業などを鑑みても現状では 1 番良いと感じました。
ですが Aurora MySQL では、Percona XtraBackup の機能が大幅に制限されており、compress オプションで使用できる圧縮形式も変更できれば更にバックアップファイルの容量を減らせるので対応されて欲しいと思います。

参考リンク