VISASQ Dev Blog

ビザスク開発ブログ

Cloud SQL for MySQL 5.7 のデータを Cloud SQL for MySQL 8.x へ DMS を利用して移行してみた

はじめに

こんにちは!DPE(Developer Productivity Engineering)チームの高畑です。

最近カーオーディオにハマっていて、スピーカーを変えたり DSP アンプを導入したりとオーディオの沼に腰あたりまで浸かってしまいました。 スピーカーケーブルをちょっと良いやつに変えたりしてみたんですが、正直違いが分かっていないので頭まで浸かるのはまだ先のようです。

現在、ビザスクでは遅ればせながら MySQL 5.7 から MySQL 8.x へアップグレードするためのプロジェクトが進行しており、既存のデータを移行するため諸々の検証を行なっていました。

検証を進めるにあたり、データの移行に DMS (Database Migration Service) を利用する方針となったので、経緯や方法をご紹介したいと思います。

移行方法の検討

当初、既存の MySQL 5.7 データベースを MySQL 8.x へ移行するために Cloud SQL のエクスポート・インポート機能を利用してデータ移行しようと計画をしていました。

cloud.google.com

エクスポート・インポート機能は mysqldump と同等のもので、SQL ファイルとしてデータを GCS へ保存して新しいインスタンスへ流し込むことができます。

実際に本番で稼働しているデータベースをクローンしたもので動作検証を行なってみた結果、220GB ほどのデータに対してエクスポートに 2 時間半・データのインポートに 7 時間の合計 9 時間半かかることが判明しました。

データ移行後の動作検証などを含めるとさらに時間がかかることが想定されたため、この方法は断念することになりました。

DMS (Database Migration Service)

上記のエクスポート・インポートは時間的に難しいと判断し、次に検討したものが DMS の利用です。

DMS とは、オンプレや Google Cloud、他のクラウドAWS、Azure...)などから最小限のダウンタイムでデータの移行を行うことができる Google Cloud が提供するフルマネージドなデータベース移行サービスです。

cloud.google.com

DMS を利用するにあたり、同じように本番のデータベースをクローンして実際にデータの移行をテストしました。

移行先のインスタンスを作成する

移行先のインスタンスはデータベースが存在しない空のインスタンスしか利用できないという制約があるため、インスタンスを新規で作成する必要があります。 DMS の画面からもインスタンスを作成することができますが、今回は gcloud コマンドを利用してインスタンスを作成しました。

gcloud sql instances create visasq-dms-test \
  --project=xxx \
  --async \
  --region=us-central1 \
  --database-version=MYSQL_8_0_34 \
  --edition=enterprise-plus \
  --assign-ip \
  --tier=db-perf-optimized-N-8 \
  --storage-size=500 \
  --storage-type=SSD \
  --no-storage-auto-increase \
  --no-enable-data-cache \
  --availability-type=regional \
  --root-password='xxxxxxxxx' \
  --database-flags character_set_server=utf8mb4,collation_server=utf8mb4_general_ci,general_log=on,log_output=FILE

移行先のデータベースが作成されたら、次に DMS の移行ジョブを作成します。

移行ジョブの作成

DMS の画面から「移行ジョブを作成」ボタンを押下して移行元・移行先に関する設定をしていきます。

開始(移行ジョブの説明)

項目
移行ジョブの名前 test-migrate-mysql8
移行元データベースエンジン MySQL
移行先データベースエンジン Cloud SQL for MySQL
送信先リージョン us-central1 (アイオワ)
移行ジョブの種類 1 回限り

移行元と移行先の GCP プロジェクトが異なる場合は、 移行元データベースエンジンを Cloud SQL for MySQL ではなく MySQL にする必要があります。

Cloud SQL for MySQL を選択するとインスタンスの ID を指定することになるのですが、DMS のジョブを作成したプロジェクトに存在するインスタンスしか表示されません(少しハマった)。

ソースの定義

接続プロファイルの作成 を選択して移行元インスタンスへ接続するための情報を入力します。

項目
接続プロファイルの名前 visasq
ホスト名または IP アドレス 移行元インスタンスのパブリック IP アドレス
ユーザ名 xxx
パスワード xxx
暗号化のタイプ 環境に応じて設定

移行先の定義

移行先のインスタンスは先ほど作成した新しいインスタンスを選択します。

項目
移行先インスタンスのタイプ 既存のインスタンス
移行先インスタンス ID visasq-dms-test

接続方法の定義

項目
接続方法 IP 許可リスト

接続方法の定義で IP 許可リストを選択すると IP アドレスが表示されますが、ここに表示されるのはインスタンスのパブリック IP アドレスで、実際にはインスタンスの画面にある「送信 IP アドレス」を移行元のインスタンスの許可 IP アドレスへ追加する必要がありました(ここもハマった)。

接続テストと実行をする

移行ジョブの作成と、移行元インスタンスへ許可 IP アドレスを追加したら接続テストをして実際にジョブを実行します。

ジョブを実行後、最初に作成したインスタンスがリードレプリカに降格、移行元のインスタンスが外部プライマリとしてレプリケーションされデータが移行されます。

また今回、移行ジョブの種類 を 1 回限り としたためデータの移行が完了した段階で自動的にリードレプリカからプライマリとして昇格されました。

結果、インポート・エクスポートでは合計 9 時間半かかっていたのに対し、1 時間ちょっとでデータの移行が完了しました。

django_session テーブルが肥大化していた問題

インポート・エクスポートでのデータ移行まわりを検証していた際に、django_session テーブルが約 2.5 億レコードのデータを抱えていて、一時テーブルにコピーするのに膨大な時間がかかっている様子が観測されました。

django_session テーブルはユーザがログインした際にセッションデータが挿入され、ユーザが自発的にログアウトの動線を踏むことでデータが削除されるため、ログアウト動線を踏まない限りはデータが削除されずに溜まり続けてしまいます。

本来であれば、clearsessions コマンドを定期的に実行して期限切れのセッションデータを掃除する必要があるのですが、その仕組みを導入していなかったためサービス開始時からの期限切れセッションデータが溜まってしまっていました。

docs.djangoproject.com

データ量が膨大で排他ロックされる可能性も考えると、DELETE コマンドを実行してデータ削除を行うにはリスクが高かったため、新規でテーブルを作成して有効なデータだけを INSERT し最後にリネーム・DROP TABLE して不要なデータを削除しました。

その結果、2.5 億レコードが 100 万レコードほどに削減することができ、ストレージの容量も 50GB 以上削減することができました。

現在では定期的に期限切れのセッションデータを削除する仕組みを導入しているため、今後は増え続けることもありません。

この状態で再度 DMS によるデータの移行をテストしてみたところ、最初の検証で 1 時間ちょっとかかっていたのに対して 20〜30 分ほど短縮することができました。

以上の結果を踏まえ、MySQL 8.x へのデータ移行は DMS を利用する方針で決定しました。

おわりに

いかがでしたでしょうか!

MySQL のアップデートプロジェクトを通じて、「MySQL 完全に理解した」から「MySQL 何も分からない」に近づいていると感じています。

まだアップデート完了まで道のりがあるので、「MySQL ちょっとわかる」になるように進めていければと思っています。

ビザスクではエンジニアの仲間を募集しています! 少しでもビザスク開発組織にご興味を持たれた方は、ぜひ一度カジュアルにお話ししましょう! developer-recruit.visasq.works