Amazon Aurora MySQL v2（5.7互換）から v3（8.0互換）へのアップグレード方法の最適解

こんにちは。[**Togetter**](https://togetter.com) を運営しているトゥギャッター株式会社でエンジニアをしている [@MintoAoyama](http://twitter.com/MintoAoyama) です。

[**Togetter**](https://togetter.com) は Twitter（X） 上のツイート（ポスト）を始めとした様々な情報を組み合わせてコンテンツを作り出すキュレーションサービスです。
2009年に誕生してから**今年で15周年**（16年目！）に突入しました 👏

<a href="https://togetter.com"><img width="1064" alt="すごいぞTogetter" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/6f388fa1-1baf-d93a-e44e-6dbdfb1efead.jpeg"></a>

また、2023年から、Twitter（X）のツイート（ポスト）を自動的に記録・ブログ形式で見る [**Twilog**](https://twilog.togetter.com) を Togetter と統合し、サービスを再開しております。
こちらも今年で15周年になります 👏

<a href="https://togetter.com"><img width="1064" alt="すごいですねTwilog" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/99dd4665-d7ea-2de8-da5f-66a4e99a50c7.jpeg"></a>

そんな Togetter / Twilog が利用する [**Amazon Aurora MySQL**](https://aws.amazon.com/jp/rds/aurora/) **をこの度 v2（5.7 互換）から v3（8.0 互換）へ移行** しました。

<img width="240" alt="Amazon Aurora" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/74923335-dead-58e9-ab88-345574257603.jpeg">

MySQL 版においては v2 の標準サポートが `2024/10/31` に終了し、（1ヶ月の無償期間を経て）`2024/12/01` から有償の延長サポートが始まってしまうので、それまでに v3 へ移行する必要があります。

[**2024年3月から始まるサポート期間が伸びるけれども費用もかかるAmazon RDS延長サポートとの付き合い方~MySQL 5.7/PostgreSQL 11を例に~ | DevelopersIO**](https://dev.classmethod.jp/articles/how-to-manage-amazon-rds-extended-support/)（2024/01/15）

移行の際には、MySQL 8 および v3 に対応するため「デフォルト文字セットの変更」「Temporary table（一時テーブル）の挙動変更」「バイナリログレプリケーションのデフォルト有効」「包括的な言語（コマンド）変更」など、アプリケーションを含む仕様変更の確認を行う必要があります。

[**Aurora MySQL バージョン 2 と Aurora MySQL バージョン 3 の比較 - Amazon Aurora**](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Compare-v2-v3.html)

この記事では、主にインフラ面において、安全・確実かつテスト・パフォーマンス検証に有用な移行手段についてご紹介します。

## "Amazon RDS Blue/Green デプロイ" で安全にテスト・昇格

Aurora / RDS をアップグレードする場合、従来であれば「**インプレースアップグレード**」という方式が考えられます。

[**インプレースアップグレードの実行手順 - Amazon Aurora**](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Upgrading.Procedure.html)

こちらは、「メニューから変更（Modify）ボタンを押し、任意のバージョンのプルダウンを選択し実行する」など（AWS CLI などによる操作も可能ですが）、各種設定項目の変更を行うような基本的な操作方法になります。

手順こそ極めてシンプルですが、実行中は本番環境（実行対象の環境）がダウンタイムに入るため、影響を最小限に抑えるためには対象アプリケーションをメンテナンスモードに切り替えたり、サービスによっては利用者が少ない深夜帯にメンテナンス作業を行うなどの工夫が必要でした。

ここに、2022年以降は「**Blue/Green デプロイ**」（ブルー/グリーンデプロイ）という方式が加わりました。

[**Amazon RDS ブルー/グリーンデプロイの概要 - Amazon Relational Database Service**](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/blue-green-deployments-overview.html)

こちらは、実行すると「本番環境（Blue）をコピー・ミラーリングしたフルマネージドなステージング環境（Green）」が作成されます。
ステージング環境は論理レプリケーション（binlog）を使用して現在の本稼働環境と同期したままになるため、サービスが稼働していても常に更新内容が反映されます。

ステージング環境の昇格に掛かる時間は1分程度になる上、その間は書き込みがブロックされるためデータ損失のリスクもありません。
さらに、昇格の際は本番環境（Blue）のエンドポイントがステージング環境（Green）にそのまま引き継がれるため、参照するアプリケーションの変更も必要ありません。

また、ブルー/グリーンデプロイを始めた後でも、不要な場合は ステージング環境（Green） ごといつでも破棄できます。
バージョンアップグレードに関わらず、データ・スキーマ変更など将来本番環境に行いたい変更を行うなど、安全に動作確認・テストを行うことができ、問題がなければそのまま昇格を行うといったフローも考えられます。

なお、今回は試していませんが、Aurora だけでなく通常の RDS でも対応しているようです。

### Blue/Green デプロイ（メジャーバージョンアップグレード）実行の大まかな流れ

1.　対象クラスターの「アクション」から「ブルー/グリーンデプロイの作成 - 新規」を選択します

![スクリーンショット_2024-09-30_9_48_58.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/9ffea246-2e3e-e767-f5ed-f54da1892d5b.jpeg)

2.　「ブルー/グリーンデプロイ識別子」「グリーンデータベースのエンジンバージョン」「グリーンデータベースのDBクラスターパラメータグループ（および DBパラメータグループ）」など必要な項目を入力・選択し、「ステージング環境の作成」を実行します

![スクリーンショット_2024-09-03_13_22_40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/c1322cd6-6656-0e60-326c-39535ad7077d.jpeg)

3.　既存クラスターに「Blue」ラベルが付与され、「Green」ラベルの付与された新しいクラスター、その間を繋ぐ「ブルー／グリーンデプロイ」が作成されます

※ 基本的に同じ構成のクラスターが作成されるため、既存クラスターにリーダーインスタンスが存在している場合は同じように作成されるのもポイントです

![スクリーンショット_2024-09-11_17_00_00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/fc51ab10-d4af-2c98-f2b7-7252c353c256.jpeg)

4.　（動作に問題がないようであれば）対象ブルー／グリーンデプロイの「アクション」から「切り替え」を選択

![スクリーンショット_2024-09-19_13_25_53.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/51c57b90-1bc7-5f63-9218-b2efc435ed2c.jpeg)

5.　実行対象のクラスターの関連情報をよく確認し、「タイムアウトの設定」を入力・選択し、「切り替え」を実行します

![スクリーンショット_2024-09-19_13_25_56.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/4345c395-b127-b43a-2f6b-c65489a7bfbb.jpeg)

6.　切り替えが完了すると、ラベルがそれぞれ「古いブルー」「新しいブルー」になります

![スクリーンショット_2024-09-19_13_29_43.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/a1e0f99d-ad98-06d5-a24c-9c3ef764f649.jpeg)

7.　対象ブルー／グリーンデプロイを削除すると、「古いブルー」「新しいブルー」のラベルはなくなり、それぞれのクラスターの関連性も（画面の表示上から）無くなります
 
※ そのままだと「古いブルー」だったクラスターは残っているため、不要になり次第破棄しておく必要があります

### Blue/Green デプロイ 実行時・実行後の注意点

Blue/Green デプロイは非常に便利な仕組みですが、実行するにあたって制約や注意しなければならない点があります。実行の際は検証環境などで事前にご確認ください。

* 基本的に同じ構成・設定のクラスターが作成されますが、「IAMロール」「Auto Scaling ポリシー」など一部の設定が引き継がれないことがあります
* 実行中はレプリケーションが常に行われますが、「テーブル名・列名の変更」など全てのスキーマ変更が反映されるわけではありません
* 実行中（レプリケーション中）にグリーンに対して書き込みを行うと不整合を起こすリスクが発生します
  * リードレプリカのように書き込みが行えないような制限は設定されていませんので取り扱いにはご注意ください
* ブルーからグリーンへの「切り替え」を行うと、再び元の状態に戻すことはできません
  * グリーンからブルーに戻すことはできないほか、バージョンアップグレードを目的とする場合は、バージョンのダウングレード自体も行えないことに注意してください
  * 当然、グリーン（新しいブルー）に対して再び Blue/Green デプロイを行うことはできますが、多くの場合は不可逆な変更を伴う要件だと思われます
    * 切り替え後に更新処理が発生している場合はそれらの消失を覚悟した上で「古いブルー」に戻したりなど、想定できるリスクを事前に理解した上でご確認いただくことをお勧めします

ワークフローや注意点については以下のページにも掲載されています

[**Overview of Amazon RDS Blue/Green Deployments - Amazon Relational Database Service**](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/blue-green-deployments-overview.html#blue-green-deployments-best-practices)

### Blue/Green デプロイ "作成" 時にエラーになる主な原因

既存クラスターなどの設定状況や、データベース・テーブルのデータ構造などによっては作成時にエラーになる可能性があります。
原因は多岐に渡ることがあるほか、Blue/Green デプロイ の作成自体にそれなりの所用時間が発生するため、エラーログ（`upgrade-prechecks.log` など）を確認しながら一つ一つに向き合う根気が必要になるかもしれません。

* 対象クラスターでは `binlog_format` を有効にする設定変更が必要です
  * パラメータグループの変更のほか、再起動を伴うためご注意ください
* MySQL 8.0 に対応するインスタンスタイプの最小は `db.t3.medium` となっています
* 「ビューを作成している場合、そのビューの参照するテーブルが存在していない」場合など、不整合が存在する場合はエラーになります。不要であれば対象ビューは事前に DROP しておく必要があります
* MySQLユーザー（= クラスターのマスターユーザー）の Hosts を `%` 以外に変更していた場合、元に戻す必要があります
* そのほか、「RDS Proxy」「クロスリージョンリードレプリカ」など、対応していない機能があるようです

## ProxySQL によるミラーリングでパフォーマンス検証

バージョンアップグレードに限ったことではありませんが、新しい環境・スペックで本番稼働する際はパフォーマンスの変化に気を配る必要があります。

従来であれば、本番相当の環境を用意し、本番相当のリクエスト量・シナリオ（クエリ内容）を用意し再現を行うことも考えるはずですが、精度を上げようとすれば一仕事になるかと思います。

そこで、少しでも楽に実現できそうな方法が、「**Blue/Green デプロイ + ProxySQL などによるミラーリング実行**」です。

![ProxySQL](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/482a65e6-d268-35bb-994e-006f8b680113.jpeg)

ProxySQL とは、高性能・高可用性を謳う MySQL プロキシサーバです。
公式の MySQL Proxy よりも安定しているという話もあり、Aurora MySQL も公式にサポートしているということでデファクトスタンダードのような状態かと思われます。

[**ProxySQL - A High Performance Open Source MySQL Proxy**](https://proxysql.com/)

[**sysown/proxysql: High-performance MySQL proxy with a GPL license.**](https://github.com/sysown/proxysql)

[**オープンソースプラットフォームで ProxySQL を使用して、Amazon Aurora クラスターでの SQL の読み取りと書き込みを分割する方法 | Amazon Web Services ブログ**](https://aws.amazon.com/jp/blogs/news/how-to-use-proxysql-with-open-source-platforms-to-split-sql-reads-and-writes-on-amazon-aurora-clusters/)

DBへの接続コストを軽減できるほか、ルーティングを細かいルールで定義できるため、クエリに応じて Writer / Reader への振り分けを自動で行えたり、「ヘルスチェック および 高速フェイルオーバーへの対応」「クエリキャッシュ」「ミラーリング」など、様々な機能に対応しています。
ProxySQL 自体をクラスタとして稼働させ、複数ノード間で設定の自動同期を行うこともできるようです。

[**Mirroring - ProxySQL**](https://proxysql.com/documentation/mirroring/)

ミラーリングを実現できれば、本番環境（ブルー）に対して実行されるクエリをステージング環境（グリーン）にもリアルタイムに近い形で実行できます。InnoDB バッファプールへのキャッシュも行われるので "暖気" も兼ねることになるはずです。

ただし、ミラーリングは非同期で実行されるため、ステージング環境に実行した結果エラーが発生しても気付きにくい状態にあります。
基本、ミラーリングによる検証はパフォーマンスを測る目的として対象クラスターのメトリクスなどを確認することをメインにし、クエリ自体の実行時エラーなどは別途グリーンに対して検証用のアプリケーションを接続して行う形になるかと思います。

### 構成例

以下に簡易的な構成図をご紹介します。

![ProxySQLを通したミラーリングの構成例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/2803bd2f-4ff4-f830-267a-12b0de407fc3.jpeg)

ここでは、（Auto Scaling に対応し）Multi-AZ で起動している EC2 上で Web App が稼働しており、リクエストに応じて Aurora MySQL にクエリを投げています。
Aurora MySQL もまた Multi-AZ で構成されており、Writer / Reader が稼働しています。
従来であればアプリケーションの実装などで、SELECT のほとんどについては Reader（リードレプリカ）に対してクエリを投げ、それ以外は Writer にクエリを投げて負荷分散を行うかと思います。

今回の検証にあたっては、リードレプリカへの SELECT については ProxySQL を介してクエリを投げるようにします。かつ、クエリのメインは「ブルークラスターのReader」に投げつつ、ミラーリングで「グリーンクラスター」に投げることにします。

※ 「リードレプリカへのSELECT」について、接続先を変えるにはアプリケーション（config 参照周り）の実装・ライブラリの対応状況などに依存します。この記事では対応済みであることを前提に記述しています :bow: 

※ リードレプリカに対して問い合わせる際は "レプリケーションによるデータ更新の遅延" が発生していることが前提になります。「SELECTした結果を更新系の処理に使う場合」など、整合性を重視する場合は Writer に問い合わせるなど考慮する必要があります

### 設定例

設定項目・内容については様々なものが考えられますが、シンプルな例をご紹介します。

```
[~]$ cat ~/proxysql/proxysql.cnf

datadir="/var/lib/proxysql"
errorlog="/var/lib/proxysql/proxysql.log"

admin_variables=
{
	admin_credentials="admin:admin;radmin:radmin"
	mysql_ifaces="0.0.0.0:6032"
}

mysql_variables=
{
	threads=4
	max_connections=2048
	interfaces="0.0.0.0:6033"
}

mysql_servers =
(
  {
    address = "（ブルークラスターのリーダーエンドポイント）"
    port = 3306
    hostgroup = 1
  },
  {
    address = "（グリーンクラスターのエンドポイント）"
    port = 3306
    hostgroup = 2
  }
)

mysql_users:
(
  {
    username = "（MySQLユーザ名）"
    password = "（MySQLパスワード）"
    default_hostgroup = 1
  }
)

mysql_query_rules:
(
	{
		rule_id=1
		active=1
		match_pattern="^SELECT"
		destination_hostgroup=1
		mirror_hostgroup=2
		apply=1
	}
)
```

今回の構成では ProxySQL に接続する対象を SELECT のみ にしているため冗長になってしまいますが、そうでない場合も、`match_pattern="^SELECT"` のように SELECT のみをミラーリングする設定が行えます。

もし、本番環境（ブルークラスター）の Writer / Reader へのリクエストの配分をステージング環境（グリーンクラスター）にも適用したい場合は、すべてのクエリを ProxySQL 経由にしつつ、細かいルールによるルーティング設定で実現できるはずです。

![ミラーリングによって SelectThroughput が揃っている様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7574/a93ccd76-a64e-2756-37da-4337982d22fd.jpeg)

期待通りにミラーリングが稼働できたら、Aurora MySQL のメトリクスを確認することになるかと思います。

例えば、「`SelectThroughput` がブルークラスター・グリーンクラスターそれぞれで同じくらいの数値になることを確認」できたら、`CPUUtilization` `FreeableMemory` `SelectLatency` `ReadIOPS` などパフォーマンスおよびコストに関連する項目を比較することになるかと思います。

弊環境では、`CPUUtilization` は若干上がってしまいましたが、それ以外は概ね同じ数値になったため、移行を決断する形になりました。

---

Amazon Aurora MySQL v2 の有償延長サポート開始の期日が迫る中、本番環境の移行に気後れしている現場もあるかもしれません。

今回取り扱った仕組みについて、もしご存じなかった方は是非ご活用をご検討ください 💪💪💪