はじめに
Aurora MySQL 5.7 のEOL に伴い、MySQL 8.0 へのバージョンアップする業務を担当した。
対象のシステムは CloudFormation (IaC) で管理されており、かつ RDS Proxy を利用している構成である。
この環境下でのアップグレードで、IaCの制約、MySQL 8.0の仕様変更、インフラの罠に次々と遭遇した。
本記事では、「DBの深淵とAWSの仕様に立ち向かった記録」 として、採用した移行戦略とハマりポイントをまとめた。
システム構成と要件
- 現: Aurora MySQL 5.7 (
db.t2.medium) - 新: Aurora MySQL 8.0 (
db.t3.medium) - 構成: CloudFormation (IaC) 管理
- 接続: Lambda -> RDS Proxy -> Aurora Cluster
比較:MySQL 5.7 vs 8.0(移行時の主要変更点)
| 比較項目 | MySQL 5.7 (Aurora v2) | MySQL 8.0 (Aurora v3) | 影響と対策 |
|---|---|---|---|
| インスタンス型式 | T2, T3, R5など幅広く対応 | T2系は非対応 (T3以降) | インスタンスクラスの変更が必須 |
| GROUP BY句 | 曖昧なカラム指定も許容 | 厳格化 (ONLY_FULL_GROUP_BY) | クエリの修正が必要になる可能性大 |
| ソート順 | GROUP BYで自動ソート | 自動ソート廃止 | 順序が重要な場合はORDER BYを追記 |
| バイナリ型 | Buffer(Node.js特有) | Uint8Array(標準) | Base64変換等のコード修正が必要 |
【移行の要件】
- ダウンタイムを最小限にする
- 問題発生時に容易にロールバックができること
- アプリケーション側の接続先変更(エンドポイント書き換え)を発生させないこと
移行戦略:「並行稼働」
今回の移行では、「旧DB(v5.7) と 新DB(v8.0) を並行して稼働させ、RDS Proxyの向き先を変える」 という戦略を採用した。
なぜ「スナップショット」(データのコピー)
公式の「Blue/Greenデプロイ機能」は、RDS ProxyやCloudFormation管理下では制約が多く使えなかった。
そこで、「メンテナンス開始直後の旧DBのスナップショット(データのコピー)を取得し、そこから新DBで復元する」 手順を取った。
また、旧DBには一切手を加えないため、データが壊れず、ロールバックがしやすいメリットもある。
実際のデプロイフロー
CloudFormationテンプレート上で、以下のようにリソースを定義した
-
準備: 旧DB (DBCluster) はそのまま定義を残す
-
構築: 新DB (DBClusterV8) を定義し、プロパティ
SnapshotIdentifierに取得したスナップショットARNを指定する -
切替: RDS Proxy のターゲットグループ定義 (RdsProxyTargetGroup) を、旧DB (DBCluster) から 新DB (DBClusterV8) に書き換えてデプロイ
-
切り戻し: 切り戻しが必要になった際のロールバックは、RDS Proxyのターゲットを DBCluster (旧) に戻してデプロイし直すだけで元の状態に戻せる
インフラ(CloudFormation)の競合回避
ここからは、実際に遭遇したエラーと解決策
1. SecretAttachmentの競合エラー
新DBを作成する際、既存の AuroraSecret (Secrets Manager) を紐付けようとして、AWS::SecretsManager::SecretTargetAttachment を定義したところ以下の様なエラーが発生した。
- エラー文: Resource handler returned message: "... already exists in stack ..."
- 原因: CloudFormationの仕様上、1つのシークレットに対して定義できる
SecretTargetAttachmentは1つだけで、既に旧DBに紐付いているため新DBにも同時に紐付けようとして競合した - 解決策: 新DB用の
SecretTargetAttachment定義を削除し、DBクラスター定義側で動的参照を使用することで解決した
DBClusterV8:
Type: AWS::RDS::DBCluster
Properties:
# SecretTargetAttachmentを使わず、ここで直接参照する
MasterUserPassword: '{{resolve:secretsmanager:AuroraSecret:SecretString:password}}'
2. インスタンスタイプ (T2 vs T3)
新DBのインスタンスクラスを、旧DBと同じ db.t2.medium に設定してデプロイしたところエラーになった
- エラー:RDS does not support creating a DB instance with the following combination.
- 原因: Aurora MySQL v3 (8.0) は、T2系インスタンスをサポートしていなかった
- 解決策: 新DBの定義のみ
db.t3.mediumに変更した
3. RDS Proxyエンドポイント名の重複
RDS Proxyのエンドポイント定義 (AWS::RDS::DBProxyEndpoint) において、論理IDを変更してデプロイしようとしたところエラーになった
- エラー:
The DBProxyEndpoint 'olc-proxyendPoint' already exists - 原因: AWS上の実体は
...-proxyEndPoint(Eが大文字) だったが、テンプレートで...-proxyendPoint(eが小文字) と書いてあった。 CFnは「名前変更=リソース置換(作り直し)」と判断したが、MySQL/AWSの仕様上、大文字小文字の違いだけでは「同名」とみなされ、「すでに存在する」と怒られた - 解決策: 既存のエンドポイント名と一字一句合わせるか、新定義の末尾に
-v8を付けるなどして完全に別名にした
アプリ・DB内部 (MySQL 8.0)
4. MySQL 8.0 の「GROUP BY」厳格化
移行において最も警戒されていたのが、SQL構文ルールの厳格化、特に GROUP BY の挙動変更
リスク1:「曖昧な GROUP BY」がエラーになる
MySQL 5.7(のデフォルト設定)では、以下のようなクエリが許容されていた
-- 5.7では動くが、8.0ではエラーになる可能性がある
SELECT class, MAX(score), student_name
FROM test_results
GROUP BY class;
GROUP BY class しているのに、集計関数を通していない student_nameをSELECTしてる。
5.7では「適当な誰かの名前」を返してくれたが、8.0では 「どの生徒の名前を出せばいいか曖昧だ」 としてエラーになる
リスク2:暗黙のソート廃止
MySQL 5.7では GROUP BY を書くと、結果が自動的にソート(昇順)されていた。
しかし、8.0ではこの仕様が廃止されたので、ORDER BY を明示していない画面では、バージョンアップ後に表示順序がバラバラになるリスクがある。
5. 実行計画 (EXPLAIN) の罠:「データ量」
「バージョンアップに伴いDBへの読み込み速度」を確認するため、EXPLAIN コマンドで実行計画を確認した。
しかし、開発環境で検証中に type: ALL(全件スキャン)が出るケースがあったので、パフォーマンスの劣化を疑った。
-
原因: 開発環境のデータ量が少なすぎたため、オプティマイザが「インデックスを使うより全件読んだ方が速い」と判断していただけだった
-
対応策: 本番想定のデータ量(数万件)を投入して再検証したら、
type: refに切り替わることを確認した
「今の実行計画」だけでなく、「本番規模のデータ量でどう動くか」を検証する重要性 を学んだ
6.データの同一性証明 (CHECKSUM TABLE)
移行前後でデータが破損していないか証明するため、これまで COUNT(件数)しか見ていなかったが、CHECKSUM TABLEコマンドを使用して、データの中身も保証されていることを確認した。
そこで、レコード数や最終更新日時も変わっていないのに、チェックサムの値だけが変わる テーブルがあった。
-
CHECKSUM TABLEコマンド
テーブルの中身(全データのバイト列)を計算してハッシュ値を出すコマンドである。
移行前後で「件数は合っているが、文字化けしてない?データ壊れてない?」を証明するために用いた -
原因:
JSON型や長大なVARCHAR型を持つテーブルにおいて、ORMが全カラム更新(値は同じ)をかけた際、論理的な値は同じでもMySQL内部(InnoDB)での物理的なバイナリ配置が整理され、チェックサムが変わると判明 -
解決策: 「チェックサムの値が違う=NG」と即断せず、最終更新日時や
SHOW PROCESSLIST(接続状況)を併用して、「業務データに変更がないこと」を多角的に証明した
まとめ
今回の移行プロジェクトを通じて、以下の知見が得られた
- インフラの競合回避: CloudFormationでは、新旧の環境で名前や設定(パスワード管理等)がぶつからないよう設計を工夫する
- SQLルールの厳格化: MySQL 8.0では、5.7で許容されていた「曖昧な書き方(GROUP BY等)」がエラーになるため、事前修正が必須
- データ検証の注意点: データの指紋(チェックサム)を確認する際、中身が同じでも「保存形式の変化」で値が変わる場合もある