初めまして、menuでエンジニアをやっている石倉 佳文です。
普段は主にmenuのマイクロサービス基盤となるGKE(Google Kubernetes Engine)の運用やmenuの横断的なインフラの改善を行なっております。
少し前のことになるのですが、本記事ではmenuのメインデータベースであるCloud SQL for MySQL 5.7からMySQL 8.4のEnterprise Plusへの移行(アップグレード)を事故なく完了させたのでどのような取り組みを行なったかをお伝えします。
背景
MySQL 5.7はすでにサポートが終了しており、Cloud SQLの延長サポートで運用していました。拡張サポートも2028年2月1日に終了することや、拡張サポートには拡張サポートの料金がCloud SQLのリソース料金とは別で上乗せされてかかるためこちらのコスト解消のためにMySQLのアップグレードを行いました。
menuの移行要件の整理
menuは従来からの基盤である巨大なモノリスサーバ、新しい基盤で増え続けるマイクロサービスといった複数のコンポーネントで構成されています。移行対象であるCloud SQLインスタンスには、これらコンポーネントのほぼ全域から更新、参照がおこなわれており影響範囲が広いことから無停止でのバージョンアップ実施はかなり難易度が高いことが想定されたため最初からダウンタイムを設ける前提で計画を進めました。
ざっくりとしたプロジェクト全体のロードマップ
今回移行対象となったのは、menu事業の複数のマイクロサービスから参照されているメインデータベースです。万が一のトラブルがサービス全体に波及するため、かなり慎重にプロジェクトを進めました。ざっくりとしたロードマップは以下の通りです。
- 移行先のバージョンの調査と移行方針の策定(技術要件の整理)
- 検証環境の構築
- コード修正
- 互換性検証
- 移行手順書の作成
- 移行リハーサル
- 本番移行
弊社には専任のDBエンジニアがいないため、移行プロジェクトはPM1名、各事業ドメインのバックエンドエンジニア3名、インフラエンジニア1名、そして私の計6名がコアメンバーとなって推進しました。
とはいえ影響範囲が非常に広かったため、コアメンバーだけで完結できるものではありませんでした。全チームへナレッジシェアを行いつつ、実際のコード修正は各チームに分担してもらいました。また、今回はダウンタイムを伴う移行だったため、各店舗様との調整などビジネスサイドの協力も不可欠でした。まさに多くの方に助けられながら、チーム一丸となって推進したプロジェクトです。
移行先DBの選定
DBの移行先として検討していたのは大まかに以下です。
- Cloud SQLを8.0にアップグレードする
- Cloud SQLを8.4にアップグレードする
- TiDBに移行する
menuでは一部のマイクロサービスのデータベースとして、MySQL互換のNewSQLである「TiDB」も利用しています。そのため、今回のタイミングでTiDBへ移行する案も挙がっていました。
しかし、本プロジェクトの最優先事項は「なるべく早くMySQL 5.7を脱却すること」です。TiDBへ移行する場合、アプリケーション側の修正規模がどれくらいになるか予測しきれないという懸念がありました。また、TiDBとCloud SQLの両方を並行して調査・検証するのはコストがかかりすぎます。
そのため、今回はまず「Cloud SQLのアップグレード」に方針を絞りました。その上で、移行先のMySQLのバージョンを8.0にするか、それとも8.4にするかの調査を進めました。
MySQL 8.0にするか、8.4にするか
バージョンアップの事前調査には、高性能なMySQLクライアントである「MySQL Shell」に用意されているアップグレードチェッカーユーティリティを活用しました。
このツールを用いて「5.7から8.0へのアップグレード」と「8.0から8.4へのアップグレード」の両方で互換性チェックを実施しました。その結果、機能的な影響や制約を確認した限りでは、menu事業の環境において「8.0に上げても8.4に上げても、変更コストはそこまで大きく変わらない」ことが分かりました。
また、データベースのサポート期限としてはCloud SQLにおけるMySQL 8.0は2026年7月に通常サポートが終了(先日サポート期間が2027/01に延長されたようです)してしまうのでせっかく大規模な移行プロジェクトを実施して8.0に上げても、すぐに延長サポートの追加コストが発生し、また次のバージョンアップ対応に追われることになってしまいます。
これらの調査結果より「実際の移行手順(移行方法)において特段の制約が見つからない限り、より新しいバージョンである8.4を採用しよう」という方針を固めました。移行方法については後ほど書きますが結果として8.4へ移行する運びとなりました。
変更差分の例
ここでは、5.7 -> 8.4への移行にあたって修正が必要だった一部の変更点について紹介します。
- GROUP BYに対するASC/DESCが使えなくなりました。
- rankが新しい予約語になり、
`rank`のように書かないと競合が発生するようになりました。rankというカラム名がいくつか存在していたので、ORMを使わずSQLを書いている部分の処理は修正が必要でした。 - DATETIME型のカラムに対して、正しいフォーマットではない文字列("yyyy-mm-dd"など)で比較を行った場合、これまではMySQL側で良しなに変換してくれていましたが、8.0以降は容赦無くエラーが出るようになりました。
- デフォルトの認証方式がmysql_native_passwordからcaching_sha2_passwordになりました。
-
character_set_serverのデフォルト値が変更されました。
| 製品 | character_set_server デフォルト |
|---|---|
| MySQL 5.7 | latin1 |
| Cloud SQL 5.7 | utf8 |
| Cloud SQL 8.4 | utf8mb4 |
6. MySQL 8.0で新しくdefault_collation_for_utf8mb4のパラメータが追加されました。役割としてはcharset=utf8mb4の時のデフォルト照合順序です。デフォルトはutf8mb4_0900_ai_ciです。
pt-upgradeを活用した互換性のないクエリの洗い出し
リリースノートや他社の事例から互換性のないクエリについて調査しましたが、それとは別にpt-upgradeを活用して効率的にクエリの洗い出しをおこなったので紹介します。
pt-upgradeとはPercona社が公開しているPercona Toolkitの一つです。二つの異なるMySQLサーバーに対してクエリを実行し、その出力結果を比較できます。
あらかじめエンジニア検証やQA検証でよく用いるリモート環境でlong_query_timeを0に設定しておき、アプリケーションの主要なクエリログを集めておき、そのsqlクエリログを使って、実験環境として構築した5.7, 8.4の環境でpt-upgradeを実行しました。基本的にはリリースノートなどで把握していた内容であり、新規で発見する物は少なかったですが、一部出力結果のソート順の違いがあるクエリを検出できました。
クエリパフォーマンスの検証
クエリのパフォーマンスについては前述したpt-upgradeの活用するために集めたsqlクエリログを用いて、5.7と8.4のEXPLAIN(8.4はEXPLAIN ANALYZEも出力)の出力結果を比較するスクリプトを作成して検知するようにしました。MySQL 5.7と8.4ではオプティマイザの挙動がことなるため、一部のクエリはバージョン間で異なるインデックスが選択されて極端にパフォーマンスが悪化するものがありますが、そのようなものを洗い出しました。かなりリーズナブルな方法かと思いますが、アプリケーションの主要なクエリはこの方法であらかたパフォーマンスの劣化を検知できていたと思います。しかし、インパクトは小さかったものの移行完了後に劣化が見つかるものはありました。
もっと正確に検証するなら商用環境のクエリをミラーリングして検証環境(8.4)に投げて確認するのが良い方法なのかなと思いましたが、準備のコストが大きいと見てこのような方法を選択しました。
苦戦した修正やバグ
パーティションの貼り直し
8系では"yyyy-mm-dd"をよしなに認識してくれなくなったためパーティションを使用していたいくつかのテーブルでパーティションの張り替えを行う必要が出てきました。基本的には既存のパーティション消して貼り直すという手順で問題なかったのですが、その中に数億レコードあるテーブルがありました。こちらについてはこれを期にクリーニングしつつ必要なものだけ残すことになりました。具体的な手順としては至ってシンプルでパーティションの張り替えは現実的ではなかったのですでに適切にパーティションを切った新規テーブルv2を作成して既存のテーブルからデータを必要な分だけ流し込み最後に新規テーブルv2を旧テーブルの名前にリネームするという作業を行いました。必要な分だけとはいえ数千万レコードあったのでレプリケーション遅延などを懸念しゆっくりとデータを流すとかなり時間を要しました。
検証環境でCloud SQLに全く通信できなくなる事象に遭遇
MySQL 8.4の検証を行う環境を構築してしばらくすると検証環境用のCloud SQLインスタンスでメンテナンスがあったのですが、メンテナンス終了後検証環境DBを参照していたアプリケーションサーバーの一部が疎通できなくなってしまいました。
正確な原因はわかっていないですが、8.4になってパスワード認証方式が変更されたことによるバグのようです。疎通できなくなったサーバーはUnixソケット通信でHAProxyを経由しDBに接続していたサーバーだったのですが、発生条件としてはUnixソケット通信を挟んでCloud SQLにアクセスしている場合ダウンタイムが発生するとその次の接続ができなくなるようです。
対策としてはTCP接続に切り替えました。懸念としてはポートの枯渇がありましたが商用でカナリア的に一部切り替え問題ないことを確認した後全て変更しました。
以下関連する記事とissueです。
照合順序のデフォルト値の変更による移行時の問題
MySQL 5.7 ではdefault_collation_for_utf8mb4は存在しませんが、utf8mb4 を指定した場合のデフォルト照合順序は以下のようになっていました。
utf8mb4 → utf8mb4_general_ci
一方で、前述した通りMySQL 8.0でdefault_collation_for_utf8mb4が新たに追加され、そのデフォルトがutf8mb4_0900_ai_ciです。
そのため、同じ utf8mb4 を指定していても、MySQL 5.7 と 8.x では デフォルトで使用される照合順序が異なります。
menuではMySQL 5.7で運用している時にcharacter_set_server = utf8mb4だけを設定しており照合順序は明示しておりませんでした。その結果MySQL 8.4では同じDDLでも生成されるテーブルの照合順序が変わる可能性がありました。
この差異を避ける対策としては以下を行いました。
- 新規テーブル作成時の照合順序の明示
-
collation_serverを設定してデフォルトの固定
また既存のデータに関しては後述するCloud SQLのインプレースアップグレードを利用することで、既存テーブルやデータの照合順序が維持されます。
移行方法の選定
DBの移行(バージョンアップ)方法として主に検討したのは「インプレースアップグレードのみを使う方法」と「ブルーグリーン移行」の二つです。
インプレースアップグレードのみを使う
インプレースアップグレードとは既存のCloud SQLインスタンスを直接アップグレードする方法です。この方法を採用するメリットとしては以下が考えられます。
- ホストが変わらないためアプリケーション側の接続設定を変更しなくて良い
- 追加のインフラコストがかからない
リスクとしては以下が考えられます。
- MySQL 5.7から直接8.4へアップグレードできず、段階的に8.0, 8.4と2段階のアップグレードが必要。そのため本番インスタンスに対して2連続アップグレード操作を行うというリスクが伴う
- 直接インスタンスをダウングレードできないため、ロールバックする必要が発生した場合の手順が多く、ダウンタイムが増加することが避けられない。
レプリケーションを利用したブルーグリーン移行
こちらは事前にレプリケーションを用いて新しいMySQL 8.4のインスタンスへデータを同期させておき、移行日にアプリケーションの接続を切り替える手法です。
メリットとしては以下が考えられます。
- 本番DBへの直接操作をしないため安全性が高く、ロールバックがインプレースのみを使う方式と比較した時に容易であること
デメリットとしては以下です。
- 一時的に本番同等のスペックのインスタンスを2重で運用することになるためコストが増大する
- 接続切り替えなどの移行手順が増える
こちらの移行方法としてバージョン差がある時のレプリケーションを行うことが可能なのか?という懸念がありましたが慎重に技術検証を行い、またGoogle Cloudへのサポートにも問い合わせて問題なく遂行できると判断しました。
システム全体への影響の大きさと万が一の切り戻しの確実性などの安全性を最優先し、「ブルーグリーン移行」を採用することに決定しました。
移行方法の詳細
移行方法の詳細について記述します。
まず、既存のCloud SQLの構成は一般的なマスターレプリカ構成でマスターDBと参照レプリカが数台いるのとあとはCDC等で利用する孫レプリカがあるというクラスター構成です。

事前の移行先インスタンス準備
移行前のグリーンなインスタンスの準備としてはインプレースアップグレードとDMS(Database Migration Service)を利用することで準備しました。(こちらはAWSのDMSとは全く別のサービスです。)
DMSとは他のクラウドからGoogle Cloudまたは、Google Cloud同士でデータベースを移行することができるサービスです。今回はなるべくダウンタイムを抑えるために移行先のインスタンスは既存のクラスター構成をそのまま準備したかったのですがCloud SQL標準のレプリケーション機能では多段レプリケーションの数に限界があり、クラスター構成での事前準備ができなかったためDMSを使用しました。こちらのDMSを使いクラスター構成として構築した移行先のCloud SQL 8.4群を移行日前日まで既存のCloud SQL 5.7からレプリケーションし続けておいて当日は接続先を切り替えるという方法を取りました。
移行先の準備の流れとしては
- 5.7の新規レプリカを作成
- 新規レプリカをバージョン8.0へインプレースアップグレード
- 新規作成した8.0のインスタンスからDMSを利用して実際に移行先として利用予定の8.4のインスタンスへレプリケーションする。
- そこから既存の構成と同じように必要なレプリカを準備する
バージョン8.0のインスタンスを間に挟んで5.7 -> 8.0 -> 8.4と多段レプリケーションを行っている理由としては大きく二つあります。
- 2つ以上離れたメジャーバージョン間のレプリケーションを直接行えない
- 5.7から8.0へのインプレースアップグレードを挟むと既存の5.7で使っている照合順序を8.0へそのまま引き継いでくれる
一応メジャーバージョンが3世代混在のレプリケーションはMySQL公式ドキュメントにてサポートされていないとあったのですが、技術検証をしてmenuとしては問題ないと判断しました。
また、menuでは5.7で利用していた照合順序であるutf8_general_ciをそのまま8.4に移行後も利用することを選択したので既存データの照合順序をそのまま引き継いでくれるのはかなり嬉しいです。
他に準備する方法として考えられるのはシンプルなダンプ&リストアがあると思いますが、こちらの方法だと既存データの照合順序の担保が難しいこと、当日の移行レプリカの準備になるのでダウンタイムが大きくなりすぎ現実的ではないことなどの理由から却下しました。
移行当日の手順
移行手順の流れとして配下の流れで実施しました。
- サービスをメンテナンスに入れる
- バッチを止める
- 5.7のマスターのread_onlyフラグの有効化
- 5.7マスター、8.4マスター予定のGTIDを比較し差分がないことの確認と、Seconds_Behind_Sourceが0であることの確認
- データの整合性チェック
- 移行先8.4DBの昇格(プロモート)
- 各アプリケーションでの接続切り替え
- QA検証、監視
- メンテ解除とバッチ再開
切り戻しの手順や各所への連絡フローなど含めてエンジニア以外のメンバーも交えてかなり時間をかけて移行手順書を構築しました。
データの整合性チェック
データの整合性チェックはMySQL標準のCHECKSUM TABLEとGoogle Cloudの出しているdata-validatorを併用して行いました。
CHECKSUMは以下のように一気に複数のテーブルを指定してしまうと、直列に処理が走り実行時間がかなり長くなってしまうので並列で実行できるようにスクリプトを書きました。
# 以下は直列で実行される
CHECKSUM TABLE テーブル名1, テーブル名2, テーブル名3;
商用データを用いた検証環境を用意していただきそこで色々検証したのですがCHECKSUM TABLEだとMySQLバージョン差があるとデータの内容が同じでも、CHECKSUMで出力される値が必ず異なってしまうものがあることがわかりました。そこで一部の値が異なるテーブルに関してはdata-validatorを利用してチェックしました。
事前検証の段階でスクリプトの実行を含め30分ぐらいかかるだろうという想定で許容できる範囲内ということで移行日当日はこの方法でデータの整合性の確認を実施することを選択しました。
Cloud SQLからBigQueryへのデータ連携パイプラインの構成変更
Cloud SQLのバージョンを上げるにあたって周辺のエコシステムとしてデータ分析で利用するBigQuery (以下BQ)へデータを同期するパイプラインがありました。こちらのパイプラインもMySQLのバージョンを上げるにあたって検証を行いましたが、結果としてバージョン5.7の時に利用していたパイプラインの構成では連携したデータに不整合が生じてしまうことがわかり構成を変更しました。
DatastreamでキャプチャしてGCSに取り込み、その取り込みイベントをPub/Subで通知してそのイベントをトリガーにDataflowのDatastream to BigQueryというGoogle Cloudが用意してくれてるDataflowのテンプレートでBQにロードするという構成を利用していました。
ここで変更が必要そうだったのはDatastreamのレプリケーションモードです。もともとバイナリログベースでレプリケーションしていたのですが、MySQL 8.4ではGTIDベースのみのサポートということで変更が必要でした。
バイナリログベースからGTIDベースのレプリケーションに変更しましたが、こちらを変更するとデータの不整合が生じてしまいました。原因としてはバイナリログベースからGTIDベースのレプリケーションに切り替えると、DatastreamからGCSに出力されるAvroファイルのスキーマが若干変更されてしまい、Dataflowのテンプレートがそれに対応できておらず、MySQLのクエリの実行順序を考慮しないままBQへマージしてしまうため不整合が発生しました。
Dataflowのテンプレートを使わずにDataflowの処理を自分たちで実装するなどの解決方法もありそうでしたが、マネージドのサービスを使っている旨みが薄れてしまうので、結果としてDatastreamから直接BigQueryへデータを連携できるDatastream for BigQueryを利用する構成へ変更しました。
こちらの変更に伴い、いくつか変更点が生じました。
- 同期されるデータの型が変わってしまう(例: もともとDECIMALで連携されていたところがNUMERICになる)
- UDFが使えなくなる
データの型については変更点をAIチームとデータ分析チームなどBQ利用者に伝えた上で合意を取りました。
UDFですが、これはDataflowのテンプレートをいじらなくても処理を拡張することができるDataflowの機能で、こちらを利用して簡単なデータの変換処理をmenuでも行っていました。Datastream for BigQueryを利用すると中間でカスタム処理が挟めないのですが、DatastreamからBQへ取り込まれた生のデータセットをそのまま利用者に提供するのではなくViewを作成し、データセットをラップした状態で提供することで、もともとUDFで行ってた処理の代替ができたので問題になりませんでした。
結果として以下のようなコンパクトな構成になりました。BQへデータを連携するときに手の込んだ変換処理を行うなどの利用はしていなかったため大きな問題はなく、運用コストも削減できこのタイミングで移行できて良かったと思います。
Enterprise Plus
Cloud SQLにはEnterpriseとその上位版のEnterprise Plusがあります。
Enterprise Plusを選択すると料金は高くなってしまうのですが、性能や可用性の点で色々と嬉しいことがあります。Enterprise Plusを選択できるのはMySQLだとバージョン8.0からです。
今回のバージョンアップに伴いEnterpriseからEnterprise Plusへも変更を行いました。
Enterprise Plusにして良かった点を実例として二つほど紹介します。
1つ目は、定期メンテナンスのダウンタイムが短くなったことです。Cloud SQLはデータベースのマイナーバージョンアップや、セキュリティの脆弱性のパッチなど定期メンテナンスが実施されます。Enterpriseだとこちらのメンテナンス時のダウンタイムが60s未満だったところが、Enterprise Plusにすると1s未満に収まるようになりました。実際に移行後にメンテナンスがあったのですが、移行前はこちらのメンテナンスでバッチが失敗し、そのリカバリー対応などの運用コストがあったのですが、移行後は実エラーとしては1件のみで大きな対応も必要なくなりました。
2つ目はData Cacheが使えるようになったことです。Data CacheとはローカルSSDにキャッシュを持つことができる機能です。大容量のキャッシュを持てるようになり、ヒット率が上がり読み込みパフォーマンスの向上を狙えます。こちらの機能の影響が全てとは言い切れませんが一部のクエリはパフォーマンスが劣化(オプティマイザの挙動変更により)していましたが、参照系のAPIは全体的にパフォーマンスが改善しました。
最後に
今回のMySQLのバージョンアップは影響範囲が大きく多くの方に助けていただきながら進め無事完了できとても感謝しています。また個人としてもコアメンバーの一人として参画できとても良い経験となりました。
最後に、menuでは今回のような大規模なインフラ刷新や、さらなるサービス成長を支えるための技術的挑戦を共に楽しんでくれるエンジニアを募集しています!
▼新卒エンジニア研修のご紹介
レアゾン・ホールディングスでは、2025年新卒エンジニア研修にて「個のスキル」と「チーム開発力」の両立を重視した育成に取り組みました。 実際の研修の様子や、若手エンジニアの成長ストーリーは以下の記事で詳しくご紹介していますので、ぜひご覧ください!
▼採用情報
レアゾン・ホールディングスは、「世界一の企業へ」というビジョンを掲げ、「新しい"当たり前"を作り続ける」というミッションを推進しています。 現在、エンジニア採用を積極的に行っておりますので、ご興味をお持ちいただけましたら、ぜひ下記リンクからご応募ください。
