インフラチームの小川です。育児効率化という名目で白物家電を買い替えまくっています。(あると思います)
最近はデータベースの同期処理を書き直していました。もともとは mysqldump を使ってダンプした SQL をストレージに保存し、別 DB にロードするようなシンプルなものでした。しかし、サービス成長によるデータの増加で「同期が遅い」「ストレージを一時的に大きく消費する」といった課題が浮き彫りとなってきました。特に前者は顕著で、サービス開発に影響が出ることもありました。
これらの課題を MySQL Shell を使って改善できたのでカンタンに紹介します。なお、本記事は AWS 上で MySQL Shell 8.0.32 を稼働させる前提で述べていきますが、クラウドに依らない一般的な内容も含まれています。
MySQL Shell とは
Oracle が開発している、mysql クライアントをより高度にしたツールです。割と昔からあります。
本記事では主にダンプ・レストア機能の紹介をしますが、それ以外にも JS/Python で DB 操作ができるといったユニークな機能もあるので、ぜひドキュメントも見てみてください。
MySQL Shell はインタラクティブモードとコマンドラインモードがあります。 シェルスクリプトに組み込む場合は後者が便利です。例えば S3 にダンプする場合は以下のようなコマンドが利用できます。
mysqlsh "${DB_USER_NAME}:${DB_PASSWORD}@${ENDPOINT}" -- util dump-schemas "$DB_SCHEMA_NAME" \ --s3BucketName="$OUTPUT_S3_BUCKET_NAME" \ --s3Region="$OUTPUT_S3_REGION" \ --output-url="$OUTPUT_S3_KEY" \ --threads=$DUMP_THREADS \ --compression=zstd
良かった点
ダンプ・レストアが速い
シングルスレッドの mysqldump と比べると、マルチスレッドの MySQL Shell は速度面で優位です。 オプションでスレッド数を増減させることができるので、コンピューティングリソースを柔軟に指定できるサーバレス環境との相性が良いです。
ダンプ・レストア先にクラウドストレージを指定できる
最近のバージョンで一部クラウドストレージ (Amazon S3, Azure Blob Storage など) へのダンプおよびレストアができるようになりました。 これによって、ダンプファイルを一時的に保存するためのローカルストレージをおさえる必要がなくなりました。
一度クラウドストレージにダンプしてしまえば、同じデータを複数の DB にレストアできるので便利です。
レジューム機能がある
--resetProgress を明示的に指定しない限り、レジューム機能がデフォルトで有効化されています。
ダンプ先にレジューム状況を管理するためのファイル (load-progress.*.json
) が置かれます。
ダンプおよびレストアは時間のかかることが多いため、なにかあったときに途中からやり直せるのは心強いです。
気をつける点
AWS: ECS のタスクロールに未対応
EC2 のインスタンスプロファイルも同様かと思いますが、S3 にダンプ・レストアする際にタスクロールを使った認可ができません。 いくつか代替案は考えられますが、今回は ECS のタスクメタデータエンドポイントからクレデンシャルを取得して環境変数にセットしてみます。
CREDENTIALS=$(curl -sS 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) AWS_ACCESS_KEY_ID="$(echo $CREDENTIALS | jq -r .AccessKeyId)" AWS_SECRET_ACCESS_KEY="$(echo $CREDENTIALS | jq -r .SecretAccessKey)" AWS_SESSION_TOKEN="$(echo $CREDENTIALS | jq -r .Token)" export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
※ 調べていて気づいたのですが、ここではエンドポイント v2 という古いものを使っています。2024/02 現在 v4 が出ているので基本的にはこちらをお使いください。
unknown option エラーが発生することがある
わけあって Debian10 という古いコンテナイメージで MySQL Shell を起動したところ、以下のようなエラーが発生してしまいました。
root@7cd96f1a10f5:/# mysqlsh --version While processing defaults options: mysqlsh: unknown option --default-character-set
--default-character-set
をセットしているつもりはないのですが、デフォルトで効いてしまっているようです。
試しに --print-defaults
してみると、その通りであることが確認できます。
root@d86a9b1956cb:/# mysqlsh --print-defaults mysqlsh would have been started with the following arguments: --default-character-set=utf8mb4 --socket=/var/run/mysqld/mysqld.sock
幸い、--no-defaults
オプションなるものが用意されているので、これを付与するとエラーが解消できます。
root@d86a9b1956cb:/# mysqlsh --no-defaults --version mysqlsh Ver 8.0.32 for Linux on x86_64 - for MySQL 8.0.32 (MySQL Community Server (GPL))
終わりに
MySQL Shell の紹介でした。
高速に同期するという観点では、Amazon Aurora であれば Aurora Clone という選択肢もあります。とはいえ制限事項もいくつかあるので、要件に合った手段が選べると良いと思います。
↓ 採用してます。ご経歴をダンプの上、ご応募待ってます。