Aurora MySQL バージョン 1（5.6 互換）→バージョン 3（8.0 互換）間の dumpInstance() & loadDump() を試す

この記事は、**[MySQL Advent Calendar 2021](https://qiita.com/advent-calendar/2021/mysql)** 6 日目のエントリです。

昨日（5 日目）は **taka_yuki_04** さんでした。

 - **[リモートからBLOB型に画像やPDFファイルを登録する方法](https://next4us-ti.hatenablog.com/entry/2021/12/05/063359)（41から始めました）**

昨年（2020 年）の re:Invent で予告されてから 1 年近く経った 11 月、ようやく Amazon Aurora に MySQL 8.0 互換（バージョン 3）が登場しました。

 - **[Amazon Aurora MySQL 3 with MySQL 8.0 compatibility is now generally available](https://aws.amazon.com/jp/blogs/database/amazon-aurora-mysql-3-with-mysql-8-0-compatibility-is-now-generally-available/)（AWS Database Blog）**
 - **[Amazon Aurora MySQL 3 (MySQL 8.0 互換) がリリースされました。](https://dev.classmethod.jp/articles/amazon-aurora-mysql-3-ga/)（DevelopersIO）**

気になるベースバージョンは 8.0.23 でした。

なお、Aurora MySQL バージョン 3 では、先の[ブログ記事](https://aws.amazon.com/jp/blogs/database/amazon-aurora-mysql-3-with-mysql-8-0-compatibility-is-now-generally-available/)にもあるとおり、Aurora PostgreSQL と同様、本家のマイナーバージョンに追従する形でリリースが行われていく予定、とのことです。

> Starting with Aurora MySQL 3, we will change this release strategy to follow MySQL Community Edition releases more closely. Each Aurora MySQL 3 release will be mapped to a corresponding MySQL 8.0 Community Edition release. For example, Aurora MySQL 3.01 maps to MySQL 8.0.23 and is wire-compatible with that specific Community Edition minor version. This means we will include all fixes and code changes that were added to that specific minor version.

※余談ですが、すでに更新を停止した（最終更新が 8.0.24 対応版）**[「MySQL 8.0 の薄い本」配布用 GitHub リポジトリ](https://github.com/hmatsu47/mysql80_no_usui_hon)**へのアクセスやクローンも若干増えた気がします。

一方、本家がすでに EoL を迎えた Aurora MySQL バージョン 1（MySQL 5.6 互換）の EoL がいつ発表されるのかも気になるところです。

MySQL でバージョンアップ、といえばレプリケーションを利用するのが定番ですが、

 - MySQL 5.6 → MySQL 8.0 のレプリケーション
 - マイナーバージョンを含む 3 バージョンをまたぐレプリケーション

は非推奨（サポート外）となっていますので（本家のサポートは Aurora には関係ないと言われればそのとおりですが）、別のバージョンアップ方法も考えておかないといけません。

インプレースアップグレードや S3 経由のエクスポート＆インポートもできますが、今回は **MySQL Shell** に用意されている（内部的にマルチスレッド処理が可能な）

 - **`dumpInstance()`**
 - **`loadDump()`**

を試してみます。

 - **[8.5 インスタンスダンプユーティリティ、スキーマダンプユーティリティおよびテーブルダンプユーティリティ](https://dev.mysql.com/doc/mysql-shell/8.0/ja/mysql-shell-utilities-dump-instance-schema.html)（MySQL Shell 8.0 公式マニュアル）**
 - **[8.6 ダンプロードユーティリティ](https://dev.mysql.com/doc/mysql-shell/8.0/ja/mysql-shell-utilities-load-dump.html)（同上）**

※といいつつ、ほぼこちら↓に書かれている内容そのままです…。

 - **[MySQL Shell の dumpInstance() を使ってMySQL5.6をバージョンアップする](https://blog.s-style.co.jp/2021/06/7926/)（SmartStyle TECH BLOG）**

# 準備

まずは**データをダンプ＆リストアする EC2 インスタンス**を用意します。

今回は、今年使えるようになったばかりの M6i インスタンスを使いました。

 - m6i.xlarge（4vCPU・16GB Mem）
 - EBS gp3 120GB（IOPS:3000）※こんなに容量は要りませんでした
 - CentOS 8（いまさらですがデータ移行に使うだけなので）

## MySQL Shell をインストール

```bash:Shellインストール
# wget https://dev.mysql.com/get/mysql80-community-release-el8-2.noarch.rpm
（中略）
2021-12-04 05:05:52 (323 MB/s) - ‘mysql80-community-release-el8-2.noarch.rpm’ saved [11492/11492]

# dnf localinstall mysql80-community-release-el8-2.noarch.rpm
（中略）
Is this ok [y/N]: y
（中略）
Installed:
  mysql80-community-release-el8-2.noarch

Complete!
# dnf install mysql-shell
Last metadata expiration check: 0:00:45 ago on Sat 04 Dec 2021 05:08:49 AM UTC.
（中略）
Is this ok [y/N]: y
(中略)
Installed:
  mysql-shell-8.0.27-1.el8.x86_64
  python3-pip-9.0.3-20.el8.noarch
  python3-setuptools-39.2.0-6.el8.noarch
  python36-3.6.8-38.module_el8.5.0+895+a459eca8.x86_64
  python39-3.9.6-2.module_el8.5.0+897+68c4c210.x86_64
  python39-libs-3.9.6-2.module_el8.5.0+897+68c4c210.x86_64
  python39-pip-20.2.4-6.module_el8.5.0+897+68c4c210.noarch
  python39-pip-wheel-20.2.4-6.module_el8.5.0+897+68c4c210.noarch
  python39-setuptools-50.3.2-4.module_el8.5.0+897+68c4c210.noarch
  python39-setuptools-wheel-50.3.2-4.module_el8.5.0+897+68c4c210.noarch

Complete!
```

## MySQL Community Client をインストール

すっかり忘れていましたがこちらもインストールします（テストデータ準備用。まあテストデータも MySQL Shell で準備すれば要らないんですけど）。

```bash:Clientインストール
# dnf module disable mysql
（中略）
Is this ok [y/N]: y
Complete!
# dnf install mysql-community-client
（中略）
Is this ok [y/N]: y
（中略）

Installed:
  mysql-community-client-8.0.27-1.el8.x86_64
  mysql-community-client-plugins-8.0.27-1.el8.x86_64
  mysql-community-common-8.0.27-1.el8.x86_64
  mysql-community-libs-8.0.27-1.el8.x86_64

Complete!
```

## Aurora MySQL バージョン 1・3 各インスタンス起動

今回は

 - バージョン 1（5.6 互換） : 1.23.4
   - r5.xlarge（4vCPU・32GB Mem）
 - バージョン 3（8.0 互換） : 3.01.0
   - r6g.xlarge（4vCPU・32GB Mem）

を立てました。

セキュリティグループのインバウンドは TCP:3306 だけ空いていれば大丈夫です（今回の実行に TCP:33060 は不要）。

## Aurora MySQL バージョン 1 側でテストデータ準備

テーブルを 4 つ、合計容量約 84GB 分用意します。
といっても、元々 10 行ずつを倍々に増やして行ったので、`dumpInstance()`でのダンプデータ圧縮率がかなり高くなりました。

```bash:クライアントで接続
# mysql -u admin -h aurora56.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com -p --ssl-mode=DISABLED
Enter password:
（中略）
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
```

```sql:テストデータ準備
mysql> create database dumpdb;
Query OK, 1 row affected (0.01 sec)

mysql> use dumpdb;
Database changed
mysql> create table dumptable1 (id int primary key auto_increment, str text);
Query OK, 0 rows affected (0.04 sec)

mysql> create table dumptable2 (id int primary key auto_increment, str text);
Query OK, 0 rows affected (0.04 sec)

mysql> create table dumptable3 (id int primary key auto_increment, str text);
Query OK, 0 rows affected (0.03 sec)

mysql> create table dumptable4 (id int primary key auto_increment, str text);
Query OK, 0 rows affected (0.04 sec)

mysql> insert into dumptable1 set str = sha2(rand(), 512);
Query OK, 1 row affected (0.01 sec)
（10行分繰り返す・dumptable2・3・4も同様に）

mysql> insert into dumptable1 (str) select str from dumptable1;
Query OK, 10 rows affected (0.01 sec)
Records: 10  Duplicates: 0  Warnings: 0
（24回繰り返す・dumptable2・3・4も同様に）
```

各テーブル 167,772,160 行のデータが生成されました。

```bash:データ保存用ディレクトリ作成
mysql> quit
Bye
# cd /var/
# mkdir dumpdata
```

# Aurora MySQL バージョン 1 のデータをダンプ

MySQL Shell を起動して`dumpInstance()` を実行します。なお、ユーザは移行しません（別途`CREATE USER`・`GRANT`したほうが良いため）。

```sh:ダンプ
# mysqlsh admin@aurora56.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com --ssl-mode=DISABLED
Please provide the password for 'admin@aurora56.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com': ************
Save password for 'admin@aurora56.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com'? [Y]es/[N]o/Ne[v]er (default No):
MySQL Shell 8.0.27

Copyright (c) 2016, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
Creating a session to 'admin@aurora56.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com?ssl-mode=disabled'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 39
Server version: 5.6.10 MySQL Community Server (GPL)
No default schema selected; type \use <schema> to set one.
 MySQL  aurora56.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com:3306  JS > util.dumpInstance("/var/dumpdata/",
                                                                           ->  {
                                                                           ->   defaultCharacterSet: "utf8",
                                                                           ->   consistent: true,
                                                                           ->   chunking: true,
                                                                           ->   threads: 4,
                                                                           ->   users: false
                                                                           ->  }
                                                                           -> )
                                                                           ->
Acquiring global read lock
WARNING: The current user lacks privileges to acquire a global read lock using 'FLUSH TABLES WITH READ LOCK'. Falling back to LOCK TABLES...
Locking instance for backup
NOTE: Backup lock is not supported in MySQL 5.6 and DDL changes will not be blocked. The dump may fail with an error or not be completely consistent if schema changes are made while dumping.
Table locks acquired
Initializing - done
Gathering information - done
All transactions have been started
WARNING: The dumped value of gtid_executed is not guaranteed to be consistent
Global read lock has been released
Writing global DDL files
Running data dump using 4 threads.
NOTE: Progress information uses estimated values and may not be accurate.
Writing schema metadata - done
Writing DDL - done
Writing table metadata - done
Starting data dump
（中略）
105% (671.09M rows / ~637.31M rows), 585.83K rows/s, 81.33 MB/s uncompressed, 661.81 KB/s compressed
Dump duration: 00:18:49s
Total duration: 00:18:49s
Schemas dumped: 1
Tables dumped: 4
Uncompressed data size: 92.84 GB
Compressed data size: 757.79 MB
Compression ratio: 122.5
Rows written: 671088640
Bytes written: 757.79 MB
Average uncompressed throughput: 82.23 MB/s
Average compressed throughput: 671.19 KB/s
 MySQL  aurora56.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com:3306  JS > \quit
Bye!
```

vCPU 数に合わせて 4 スレッドで実行したところ、Aurora のコネクションは 6 本になりました（最初の MySQL Shell 経由での接続 1 本を含む）。
![20211204_mysql56dump_thread.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123899/adf289e8-8beb-5f07-850d-d5a701206f0e.png)

この間の CPU 使用率は 100% に達することはありませんでした。
![20211204_mysql56dump.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123899/dfda7887-c075-4b12-7763-c369642c54dc.png)
※データの圧縮率によって変わってくるはずです。

# Aurora MySQL バージョン 3 にリストア（ロード）する

ダンプしたデータをリストアします。

```sh:リストア
# mysqlsh admin@aurora80.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com
Please provide the password for 'admin@aurora80.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com': ************
Save password for 'admin@aurora80.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com'? [Y]es/[N]o/Ne[v]er (default No):
MySQL Shell 8.0.27

Copyright (c) 2016, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
Creating a session to 'admin@aurora80.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 26
Server version: 8.0.23 Source distribution
No default schema selected; type \use <schema> to set one.
 MySQL  aurora80.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com:3306 ssl  JS > util.loadDump("/var/dumpdata/",
                                                                               ->   {
                                                                               ->     loadDdl: true,
                                                                               ->     ignoreVersion: true,
                                                                               ->     threads: 4
                                                                               ->   }
                                                                               -> )
                                                                               ->
Loading DDL and Data from '/var/dumpdata/' using 4 threads.
Opening dump...
Target is MySQL 8.0.23. Dump was produced from MySQL 5.6.10
WARNING: Destination MySQL version is newer than the one where the dump was created. Loading dumps from different major MySQL versions is not fully supported and may not work. The 'ignoreVersion' option is enabled, so loading anyway.
Scanning metadata - done
Checking for pre-existing objects...
Executing common preamble SQL
Executing DDL - done
Executing view DDL - done
Starting data load
WARNING: dumpdb@dumptable2@0.tsv.zst error 3719: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
（中略）
```

実は[先の参考記事](https://blog.s-style.co.jp/2021/06/7926/)にデータの変換手順が示されていたのですが、`utf8`を`utf8mb4`に変換しておかないとこのような`WARNING`が表示されます。

```sh:
1 thds loading \ 100% (92.84 GB / 92.84 GB), 5.73 MB/s, 4 / 4 tables done
WARNING: dumpdb@dumptable2@@844.tsv.zst error 3719: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
Executing common postamble SQL
Recreating indexes - done
2114 chunks (671.09M rows, 92.84 GB) for 4 tables in 1 schemas were loaded in 1 hour 30 min 6 sec (avg throughput 17.18 MB/s)
2114 warnings were reported during the load.
 MySQL  aurora80.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com:3306 ssl  JS > \quit
Bye!
```

リストアも 4 スレッドで実行したら Aurora のコネクションは 6 本になりました（最初の MySQL Shell 経由での接続 1 本を含む）。
![20211204_mysql80restore_thread.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123899/14ce1e0f-6e42-055e-275e-8f4d380482cd.png)
（終了後しばらく放置していました）

リストア時の CPU 使用率は、途中まで 95% 前後で完了の約 10 分前に 50% 前後に下がりました（↑のとおり当該時間帯のコネクションはずっと 6 本のままでした）。
![20211204_mysql80restore.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123899/2c72cc22-1a83-ff17-628b-30d9dd7deaa4.png)

雑に試しただけですが、MySQL Shell の`dumpInstance()`・`loadDump()`でも Aurora MySQL バージョン 1 → 3 間のデータ移行ができそうなことがわかりました。

ダンプ→リストア全体の時間短縮をしたい場合は、[MySQL Shell 8.0 公式マニュアル](https://dev.mysql.com/doc/mysql-shell/8.0/ja/mysql-shell-utilities-dump-instance-schema.html)にあるようにスキーマ（DB）単位・テーブル単位に分けて順次ダンプしつつ、ダンプが終わったものから（全スキーマ・テーブルのダンプ完了を待たずに）順次リストア（ロード）していく、という手法も可能です。

---

# 余談

## スナップショット圧縮？

テスト実施後、Aurora 各インスタンス（クラスタ）のスナップショットを取ってみたところ、Aurora MySQL バージョン 3 では容量が圧縮されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123899/e2644b96-b22d-c7f2-2e59-6a74381ac006.png)

## パフォーマンスインサイトが…

デフォルトのパラメータグループの設定でパフォーマンスインサイトを ON にしたところ、「待機別」で表示される待機イベントが明らかに少なく…。
![pitest80_event.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123899/99a354ca-e556-6825-b6b5-8e027bacb5d6.png)

↓のとおり、SQL 自体は記録されているようなのですが。
![pitest80_sql.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123899/3ccf6d3d-27f1-dd38-8d54-44741c708ffb.png)

以前のバージョンではデフォルトのパラメータグループのままでもパフォーマンスインサイトの待機イベントが記録されたのですが、Aurora MySQL バージョン 3 ではパフォーマンススキーマの設定を調整する必要があるんでしょうかね？と思って`performance_schema`を`1`にしてみたものの、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123899/3c8f106b-8401-a517-29a5-5333e37d9cbe.png)

やっぱり変ですね（もっと細部の設定が必要？それとも、新しくなったパフォーマンススキーマの仕組みとパフォーマンスインサイトの相性が悪い？）。

---

明日（7 日目）は **ham0215** さんです。

 - **[MySQLの行ロックを図解](https://qiita.com/ham0215/items/57f84a9bf28cd2635dac)**