古いEC2上のMySQLをAurora Serverless v2にしようとして、結局普通のAurora + Graviton2に落ち着いたという話

先日社内用のwebアプリで使われていた古いEC2上のMySQLをAurora Serverless v2にしようと試して、結果的に普通のAurora + Graviton2 + MySQL8に落ち着いたためその記録です。

# 前置き

専門のインフラやクラウドのエンジニアでは無く、その辺のクラウド利用経験の年数も浅いため知識などが微妙だったり粗かったりする点はご容赦ください。

# なぜEC2からAurora移行したのか

EC2上に組まれたMySQLと比べてAuroraのメリットは世の中に色々な記事等があるためここで触れるまでも無い・・・感じはありますが、一応軽く触れておきます（ついでに何故MySQLもアップデートなどをしたのかなども触れておきます）。

- なるべくマネージドのものに寄せて保守・運用で楽をしたいと感じていました。
- 稀にEC2上のMySQLが調子が悪くなり、色々調整してもMySQLもしくはインスタンスの再起動などをしないと復帰してくれないケースが発生しており、その辺がAuroraだと楽になるのだろうか？と思いました。
- 将来Graviton3やGraviton4と段々と新バージョンの展開が増えてくると思いますが、その辺への移行もしやすいようにGraviton2のAuroraにしたいと思いました（Auroraの場合特にArmベースなどを意識しなくとも使えるマネージドのサービスなのは楽で助かります）。
- MySQLバージョンが古く不便な点などもぼちぼち経験し、EoLを迎えてからも結構経過しているためMySQLもアップデートしたいと感じました。
- EC2上にMySQLを設定するよりも組むのが非常に楽です。
- アップデートやバックアップ、メトリクス設定などで楽をしたいと思いました。
- 単純にAuroraの方が速いのでは？と期待していました。
- 引き継いだ当初よりもS3やAthenaなどの併用と定期的なデータ削除処理などを加えてぐぐっと必要ディスクサイズが小さくなった（元はテラバイト単位で利用していたものの、200GBくらいに小さく出来てきた）ものの、稼働中にEBSのディスクサイズを小さくするのはあまりやりたくない作業（EC2のディスクサイズを大きくするのはダウンタイム無しでいけますが・・・）に感じたため、どうせなら移行しようか・・・と判断しました（Auroraだとディスクサイズの拡張なども意識しなくとも良くなるのと、EBSよりも縮小面でぐぐっと楽になるため）。
- Aurora Serverless v2がGAとなり、これは移行を試してみる好機なのでは？と判断しました。

# なぜここまで古いバージョンのMySQLをEC2上で使い続けたのか

- 社内の閉じられた環境のみの利用のためのMySQLだったため、通常のプロダクトよりもアップデートや移行などに神経質にならなくとも良いか・・・と思っていました。
- 社内用のアプリなため、社内でも小規模チームとなり1人か2人で全部作業していることが多く、他の改善点なども大量にあったためそちらの優先などもしていました。
- 自身が前職までデザイナーをしていたり、今のチーム所属になるまではゲームクライアントのエンジニアをしていたり・・・といった具合だったため「Linuxよく分からん」「AWSよく分からん」という状態だったためなんだかんだ慣れたり知見が増えてくるまで放置となっていました。
- 引き継いだ当初では対象のアプリが「Python2系」「テストが皆無」「コードが非常に難解になっている」「docstringなどのコードドキュメントが皆無」「Lintが設定されていない」「プロジェクトコードが把握出来ていない箇所が多すぎる」「開発環境がVirtualBox」「他にも切り落としたり移行した方がよいAWS利用のものがある」といった具合だったため、「Python3系移行」「ほぼ全ての処理で単体テストを整備し、日々自動実行されるように整備する」「全コードの内容を把握してリプレイスなども必要に応じて少しずつ実施してコードの認知的複雑度を下げる」「全コードにdocstringを追加し、docstringのチェック用のLint縛りも設ける」「各種PythonのLintを整備」「開発環境のDocker移行」「他のAWSサービス関係の作業を行ってコストダウンなどを実施」とMySQLのAurora移行以外のところの改善にも結構時間がかかりました（もちろん1人か2人の少人数で作業していたのでその間の要望や機能開発なども並行しています）。
  - ※単体テストの整備やコードの把握などができていないと影響把握や障害時の復帰までの時間が長引いたりしそうだったためその辺の整備等を優先しています。
- どうせ時間をかけて移行するならAurora Serverless v2がGAになってからそちらを試した方が一層マネージド感が増えて保守が楽になるのでは？と思いGAになるまで移行を見送っていました。

# 最初はAurora Serverless v2を試すものの・・・

元々Aurora Serverless v2が移行先として第一候補だったのと、Aurora Serverless v2がGAになった直後にJAWSのイベントが開催されたのでそちらに参加してみても「Aurora Serverless v2で良さそうだ」と感じられたため最初はAurora Serverless v2へ移行する形で進めていました。

https://dev.classmethod.jp/articles/aurora-serveless-v2-deep-dive/

Aurora利用経験も浅いこともあり、なにかあった時に元のEC2環境に戻せられるように移行作業中はEC2とAurora両方とも稼働させた状態にしてテーブルを少しずつ移行しバッチ処理やユーザー利用・各種メトリクスの様子を見つつAurora側の比率をじわりじわりと増やす・・・という形で対応を進めました。

Aurora Serverless v2ではACU（スペックの値）の上限を決められるため、このくらいであれば予算的にOKでしょう・・・というところで上長相談の上で上限値を設定していました。

しかしながら移行途中でACU上限に張り付くようになり、エラーも頻発するようになってしまいました。どうしようか・・・と悩んだ結果、上長に再相談した結果一旦EC2側に移行したものを戻しつつAurora Serverless v2ではなく通常のAuroraへと移行させていただく形に変更としました。

1分くらいのごく短時間でも高速にスケーリングしてくれる点、スケーリングで何も考えなくてもよしなに対応してくれる点、コールドスタート的な状態が発生しない等々非常に魅力的点も多いAurora Serverless v2ですが、単純なスペックに対するコストはEC2や普通のAuroraに比べて結構高めになります（その分非常に楽が出来ます）。

v2自体がv1に対してACU単位でのコストが2倍になっている点、北米リージョンと比べると東京リージョンの料金が結構高い点（北米が`$0.12`に対して東京が`$0.2`）、そもそものServerlessのACU単位での料金が普通のEC2やAuroraに比べて結構割高感がある点、（他のAWSサービスもそうですが）円安が進んでいて余計にコストが高くなる・・・という点から0.5ACU（1GBメモリ相当）で約1万円くらいかかります。スペック辺りのコストは大分高くなります（北米環境とかであれば体感的にここまで極端ではないのかもしれませんが・・・）。

他のEC2やAuroraでのr6g.large（メモリ16GB）で値段をざっくり比較すると、EC2の場合は約12000円、通常のAuroraは約31000円な一方で、Aurora Serverless v2の場合約16万円くらいになります。

もちろん利用率が低い間はコストが下がるので節約にはなりますが、これだけ差があると割とスペックダウン中のコスト減を加味しても普通のAuroraとかの方が安くスペックの良いものが確保できる・・・ということも発生し得ます（というか今回の私のユースケースでは発生しました）。

r6とかのメモリの多いインスタンス比なので、CPUとかは実は速いのでは？という感じも少しありますが、CPUもメモリ相応といった感じでCPU負荷的に移行途中で厳しくなっています。

割と以下のレビュー記事に感覚が近いです。

> Aurora Serverless v2 is too expensive!
>
> In general, I think Aurora Serverless v2 is too expensive.
> ...
> So using Aurora Serverless v2 makes sense for workloads that are idling for more than 77% of the time compared to on-demand instances. Or even worse, only for workloads idling more than 96% of the time compared to reserved instances with a three-year term and all-upfront payment.
>
> That’s a showstopper for most scenarios, in my opinion. I’m afraid Aurora Serverless will fail not because of technical obstacles but because of the pricing model this time.

DeepL翻訳:

> Aurora Serverless v2は高すぎる!
>
> 一般的に、Aurora Serverless v2は高すぎると思います。
...
だから、Aurora Serverless v2を使うのは、オンデマンドインスタンスと比較して77%以上の時間アイドリングしているワークロードに意味がある。さらに悪いことに、3年契約で全額前払いのリザーブドインスタンスと比較すると、96%以上の時間アイドリングしているワークロードにしか使えない。
>
>これは、ほとんどのシナリオでショーストッパーになると私は思います。Aurora Serverlessが失敗するのは、技術的な障害ではなく、今回の価格モデルのせいではないか、と私は思っています。

https://cloudonaut.io/review-aurora-serverless-v2/

# 一方でAurora Serverless v2が向いているケースも結構色々あるという所感

今回の私のユースケースでは向いていない・・・という感じでしたが、一方で非常に高速にスケールしてくれたり、スケール時にコールドスタート的なものが発生しなかったり、通常のAuroraのDBクラスターに混ぜられたり・・・といった仕様はとても魅力的に感じており、ハードなユースケースでお金を結構かけてもサービスが落ちないことを優先する・・・といったケースなどで色々向いているケースも勿論あると考えています。

例えば一例として以下のようなケースで良いのではという所感です。

- 大きな広告（テレビCMなど含む）の実施などによる極端な負荷増が発生し、且つその負荷がどのくらいになるのか、どのくらい短時間でスケールが必要になるのかが正確に読めにくい場合。また、サービスが落ちると宣伝費が大きく無駄になってしまうのでコストをかけてでもサービスが落ちないことを優先したい場合。
- ゲームのリリース直後など、極端なユーザー流入＆負荷が読みづらいケースなどで非常に短時間でのスケール等が必要な場合。
- 突発的に実施され短時間で極端な負荷の動きをするイベントやキャンペーンなどの負荷対策。
  - 通常時の「大体このくらいのスペックはあった方が良いよね」というスペック分は安価な通常のAuroraを使いつつ、こういったイベントなどの負荷はAurora Serverless v2みたいに短時間でスケールしてくれるものに（DBクラスターに混ぜたりして）負荷を集中させる・・・といった使い方も良いと思います。

Aurora Serverless v2が長いこと（2年くらい？）Preview状態が続いて、やっとGAになった・・・という感じで結構SNS上なども熱意のあるポジティブな意見が多かった点や事前情報などを読んだり聞いていたりしたところでは「今後は大体のケースで脳死でAurora Serverless v2を選べば良いのでは・・・」と感じてしまっていたのですが、ユースケースによっては向いているケースも色々あると思われる一方で微妙なケースもある・・・という所感なので、脳死で選択せずに検証した方が良いなと感じました（反省）。

# 最終的に通常のAurora + Graviton2 + MySQL8の組み合わせに落ち着く形に

その後は「社内用だしそこまで神経質にならずに今まで通りEC2で運用するべきか？」「普通のAuroraへの移行を試してみるか？」と悩んだのですが、結果的には上長相談の上で保守負担を減らしたりMySQLバージョンも新しくしたいと思ったため普通のAuroraへの移行を試してみる形にしました（マネージドの面とコストの面を加味してEC2とAurora Serverless v2の中間と言えそうなバランスの普通のAuroraを選択しています）。

前述の通りEC2と比べると普通のAuroraでも結構コストが高い感じではありますが、Graviton2の新しいインスタンスタイプになる点、Aurora自体が普通のMySQLよりも速い（スループットの数値が良い）という記事を結構見かけていた点、MySQL8にアップデートとなってMySQL自体も速くなるのでは・・・という期待もあり、EC2ではm4.xlargeになっていた点をr6g.largeで一段階下げる形でも十分なのでは？という期待もありました（一段階下げる形であればEC2とそこまでコストが大きく変わらないという点も加味し）。

ただし使ってみたら思ったよりも速くなく、その場合にはやむを得ないのでr6g.xlargeを使わせてください・・・という点は上長に事前に許可いただいています。

※社内用なので稀に10分くらいダウンタイムが発生してしまってもまあ許容範囲でしょう・・・と判断してシングルAZを選択しています。

https://dev.classmethod.jp/articles/decision-method-for-aurora-multiaz/

結果的には一通りの移行を終わらせた状態でr6g.largeのままでもメトリクスを見ている感じ大丈夫そう（Aurora Serverless v2の時のようにCPU使用率が100％になったりせずに大体低い水準になっている）という点と、実際にエラーが出たりもせずに安定稼働してくれています（Graviton2などがやはり速いという感じなのでしょうか・・・？）。

今のところ移行してから1か月弱という感じですが、もう少し（1か月強程度まで）様子を見たらEC2側を切り落とそうかなと考えています。

インスタンス自体はlargeで一段階下げられそうな点とEBSのディスクサイズの無駄がAurora移行で減るため結果的にはトータルでは2万円程度の月額の節約になるのとマネージドの領域が増えて色々楽になるのではと期待しています。

# Aurora移行で躓いた点

MySQL8で変わっていた点などが多めですが、Aurora + Graviton2 + MySQL8へ移行するにあたって引っかかった警告やエラーなども触れておきます。

## デフォルトの照会順序が変更になった影響で警告が出た

引き継いだ時の既存の実装分に合わせる形でutf8_general_ciの照会順序を使っていたのですが、MysQL8ではそれらが警告が出るようで、utf8mb4_0900_ai_ciやutf8mb4_binを使う必要があるようだったため一通りそれらの照会順序に移行しています。

https://qiita.com/seltzer/items/8b5d8a61591e72715d5b

## テーブル作成時にInteger display width is deprecated and will be removed in a future releaseという警告が出るようになった

今まではテーブル作成や同期などの処理で発行されるCREATE文でBIGINT(20)みたいな括弧と数字付きの記述を使っていたのですがそれがMySQL8では警告が出るようになったようなので、括弧などを使わずにBIGINTといった記述のみで対応する形に調整しました。

https://stackoverflow.com/questions/58938358/mysql-warning-1681-integer-display-width-is-deprecated/59123431

## 開発環境用のMySQL上でのユーザー生成で躓く

開発環境ではコスト的にAuroraは使わずにDocker + MySQL8で扱う形にしたのですが、ユーザー生成用のスクリプトでgrantなどを実行している箇所で引っかかりました。

どうやら新規ユーザー作成時の挙動が少し変わっているようでその辺の微調整が必要になりました。

https://qiita.com/egnr-in-6matroom/items/e77dfc719ed3dfbe0027

## 今まで発生していなかった箇所でMySQL server has gone awayのエラーが発生するようになった

今までは発生しなかった箇所で高確率でMySQL server has gone awayのエラーが発生するようになりました。

タイムアウトなどのAurora上の設定の問題か・・・？と思い色々パラメーターグループの値を調整したりEC2側と比較したりしていたのですが改善しないところが1か所発生したり・・・といった具合で、結局そういったエラー発生時場合にはリトライ＆再接続させる・・・といったデコレーター設定を追加しています。その後はエラーも無く非常に安定しています。

## 最初デフォルトのパラメーターグループを使用していて躓く

Aurora（RDS）に慣れていなかった・・・というのが大きいのですが、最初何も考えずにデフォルトのパラメーターグループを使用していました。

MySQLのパラメーターを変更したくなった場合はmy.cnfを変更しつつ稼働中のMySQLでも設定を変更する・・・みたいなことをすればOKでしょう・・・とEC2の感覚でいたのですが、RDSでは稼働中の設定をMySQL上でのSQLで変更が効かず、そしてデフォルトのパラメーターグループを使ってしまうと変更にRDSの再起動が必要になるということが把握できておらず最初躓きました。

> RDS作成時にデフォルトで作成されるパラメータグループは設定変更ができません。
> また、パラメータグループを変更するにはRDSの再起動が必要です。
> よってデフォルトのパラメータグループは使用せず、必ず新規で作成しましょう。

https://www.it-ouji.com/2021/02/16/aws-rds%E3%81%AE%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AE%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AF%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%AA/

その後はちゃんとパラメーターグループを作成してAuroraへ反映し、そちらであれば変更が効いたり再起動しなくとも設定が反映されたり・・・といった具合で落ち着いています。別のインスタンスを作成する時などもパラメーターが使いまわしできてインスタンスと設定が切り離されているのは快適な仕組だなと思いました。

# 参考文献・サイトまとめ

https://dev.classmethod.jp/articles/aurora-serveless-v2-deep-dive/

https://dev.classmethod.jp/articles/aurora-serverless-v2-ga/

https://cloudonaut.io/review-aurora-serverless-v2/

https://dev.classmethod.jp/articles/decision-method-for-aurora-multiaz/

https://qiita.com/seltzer/items/8b5d8a61591e72715d5b

https://stackoverflow.com/questions/58938358/mysql-warning-1681-integer-display-width-is-deprecated/59123431

https://qiita.com/egnr-in-6matroom/items/e77dfc719ed3dfbe0027

https://www.it-ouji.com/2021/02/16/aws-rds%E3%81%AE%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AE%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AF%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%AA/