はじめに
こんにちは!DPE(Developer Productivity Engineering)チームの高畑です。
最近カーオーディオにハマっていて、スピーカーを変えたり DSP アンプを導入したりとオーディオの沼に腰あたりまで浸かってしまいました。 スピーカーケーブルをちょっと良いやつに変えたりしてみたんですが、正直違いが分かっていないので頭まで浸かるのはまだ先のようです。
現在、ビザスクでは遅ればせながら MySQL 5.7 から MySQL 8.x へアップグレードするためのプロジェクトが進行しており、既存のデータを移行するため諸々の検証を行なっていました。
検証を進めるにあたり、データの移行に DMS (Database Migration Service) を利用する方針となったので、経緯や方法をご紹介したいと思います。
移行方法の検討
当初、既存の MySQL 5.7 データベースを MySQL 8.x へ移行するために Cloud SQL のエクスポート・インポート機能を利用してデータ移行しようと計画をしていました。
エクスポート・インポート機能は mysqldump
と同等のもので、SQL ファイルとしてデータを GCS へ保存して新しいインスタンスへ流し込むことができます。
実際に本番で稼働しているデータベースをクローンしたもので動作検証を行なってみた結果、220GB ほどのデータに対してエクスポートに 2 時間半・データのインポートに 7 時間の合計 9 時間半かかることが判明しました。
データ移行後の動作検証などを含めるとさらに時間がかかることが想定されたため、この方法は断念することになりました。
DMS (Database Migration Service)
上記のエクスポート・インポートは時間的に難しいと判断し、次に検討したものが DMS の利用です。
DMS とは、オンプレや Google Cloud、他のクラウド(AWS、Azure...)などから最小限のダウンタイムでデータの移行を行うことができる Google Cloud が提供するフルマネージドなデータベース移行サービスです。
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
コマンドを定期的に実行して期限切れのセッションデータを掃除する必要があるのですが、その仕組みを導入していなかったためサービス開始時からの期限切れセッションデータが溜まってしまっていました。
データ量が膨大で排他ロックされる可能性も考えると、DELETE コマンドを実行してデータ削除を行うにはリスクが高かったため、新規でテーブルを作成して有効なデータだけを INSERT し最後にリネーム・DROP TABLE して不要なデータを削除しました。
その結果、2.5 億レコードが 100 万レコードほどに削減することができ、ストレージの容量も 50GB 以上削減することができました。
現在では定期的に期限切れのセッションデータを削除する仕組みを導入しているため、今後は増え続けることもありません。
この状態で再度 DMS によるデータの移行をテストしてみたところ、最初の検証で 1 時間ちょっとかかっていたのに対して 20〜30 分ほど短縮することができました。
以上の結果を踏まえ、MySQL 8.x へのデータ移行は DMS を利用する方針で決定しました。
おわりに
いかがでしたでしょうか!
MySQL のアップデートプロジェクトを通じて、「MySQL 完全に理解した」から「MySQL 何も分からない」に近づいていると感じています。
まだアップデート完了まで道のりがあるので、「MySQL ちょっとわかる」になるように進めていければと思っています。
ビザスクではエンジニアの仲間を募集しています! 少しでもビザスク開発組織にご興味を持たれた方は、ぜひ一度カジュアルにお話ししましょう! developer-recruit.visasq.works