Aurora MySQL 5.6->8.0/PostgreSQL 10・11 -> 13へバージョンアップした話。アソビューのDB移行戦略

この記事は、アソビュー! Advent Calendar 2022の19日目です。本日は、裏面の記事は、下記の記事です。こちらもよろしければご覧ください。

tech.asoview.co.jp

アソビューでSREを担当している鈴木です。SREについては、12日目の

アソビューにおけるSREとは?4,000万人のアクセスに耐えられるインフラと高い信頼性を目指して - asoview! TECH BLOG 

にも紹介しているのでよければこちらもご覧ください。上にも書いた通り、SREでは、ミドルウェアの運用保守も担当しており、12月5日にアソビューで利用しているデータベースのバージョンを更新しました。 これらのプロセスを実行する上で、どういう手順でバージョンアップを実施したのか、実際に裏側ではどう言う問題が発生したのかとかのお話を紹介しようと思います。

アソビューで利用しているデータベースについて

アソビューで利用されている技術については、下記にこちらの記事で紹介しています。

アソビューを支える技術 2020. アソビュー Advent Calendar 2020の2日目です。 | by disc99🐼 | asoview-engineering | Medium

リレーショナルデータベースについては、バージョンアップする前には、下記の三つのバージョンのデータベースを利用していました。

  • Aurora MySQL 5.6
  • PostgreSQL 10
  • PostgreSQL 11

これらのデータベースを今回のバージョンアップにおいてAurora MySQL 8.0/PostgreSQL 13へと更新しました。

データベースの規模としては、下記の感じです。

  • クラスタ数 8クラスタ
  • テーブルデータ総量 約700G

このデータベースで下記のデータ数を支えています。(2022年3月末時点)

  • 会員数 620万人
  • 口コミ数 78万件
  • プラン数 2.6万件
  • 施設数 8,800施設

今回は、この規模のデータベースをバージョンアップしました。

Auroraバージョンアップの大まかな流れについて

大まかな流れていうと、今回のバージョンアップにおいては、下記のプロセスで実施しました。

  1. バージョンアップ前後の変更点、移行方法について調査
  2. 評価環境で流れているクエリをキャプチャして、影響のあるクエリの洗い出し
  3. 評価環境のDBをバージョンアップして検証
  4. 評価環境におけるパフォーマンス検証
  5. 本番環境に適用するための手順書とタイムテーブルの作成
  6. メンテナンス日の決定と利用者へのアナウンス
  7. 本番環境のデータベースのバージョンアップ
  8. 本番環境の一定期間の重点監視

バージョンアップ前後の変更点、移行方法について調査

最初に、SREが主体となって、バージョンアップに関して下記の情報を共有する勉強会を開催しました。

  • バージョンアップにおける大まかなステップとチーム毎の役割分担について
  • 主な新機能をピックアップ
  • パラメータの変更・廃止・追加情報
  • 仕様変更情報

これらの情報を共有して、特にMySQL 8.0への更新は、非常に大きな変更になると言うことを開発側に共有しました。

評価環境で流れているクエリをキャプチャして、影響のあるクエリの洗い出し

次に、一定期間のクエリ発行ログを記録して、それをバージョンアップ後のDBに再生して互換性のチェックを行いました。 DML系のSQLに関しては、この方法での検証は難しかったので、主にSelect系のクエリの互換性を重点的にチェックしました。

ここでは、下記の問題のクエリを検出して、開発側に修正依頼をかけるというプロセスを実施しました。

  • パフォーマンス劣化するクエリ
  • バージョンアップ後に文法エラーになるクエリ

ここでは、Mysql8.0において予約語になり、バージョンアップ後にエラーとなってしまうクエリの検出や実行計画が変わることにより、大幅に劣化するクエリの検出を行いました。 クエリの数としては、100件ほどのクエリを事前に抽出して対応することができました。

評価環境のDBをバージョンアップして検証

準備が整ったので、評価環境のDBを実際にバージョンアップしていきます。 ここでは、後ほど必要になる本番環境の手順書の元となる手順書を作成して、本番環境の更新が安全に実施できるようにしておきます。

実は、評価環境をバージョンアップ後に実際に稼働してみると、致命的な問題が発覚して全く環境が動作しなくなってしまいました。 そのため、バックアップから環境を戻すという作業も発生しています。

最近、AWSからAuroraのブルー/グリーンデプロイについてアナウンスがありましたが、この時にこの機能があればすごく嬉しかったのにと思いました。 次回、バージョンアップがある時には、この仕組みを使ってより簡単にバージョンアップ検証をしていきたいと思います。 この仕組みは、バージョンアップ検証中に戻したりあげたりするのに便利そうな仕組みです。

aws.amazon.com

今回は、それがなかったので、巻き戻す際に、一部評価環境のデータが巻き戻ってしまうなどの課題は発生しました。

評価環境におけるパフォーマンス検証

評価環境を使って、想定したシナリオに対して負荷検証を実施していきます。ここは評価チームにより実施されます。 Asoviewでは、Gatlingを使って繰り返し繰り返し想定したのパフォーマンスが出るまでテストを実施していきます。

アソビューにおけるGatlingの使い方については、下記もご参照ください。

負荷テストを進めるためのワタシ的重要なポイント - asoview! TECH BLOG

gatlingで負荷試験を実施する方法 - asoview! TECH BLOG

ここでは、10日間くらいかけて、繰り返し実施していき、最終的には、パフォーマンス上の問題長いと判断することにより完了となりました。

本番環境に適用するための手順書とタイムテーブルの作成

今回のデータベースの変更は、非常に大きな変更であったために、社内でリスク軽減のための体制づくりを行いました。 アプリケーション開発者の方はもちろん、事業側のチームにも出てもらい、何かあった時の顧客への連絡体制やユーザへの連絡体制なども整える形で進めました。

手順書については、SREチームないで入念にレビューを重ね、時間に無理はないかとか、バッファは十分かどうかとか、 事前に、本番環境のスナップショットを使い、バージョンアップを実施テストをして、時間の妥当性の検証などを行いながら タイムスケジュールの作成と手順書の作成を行いました。

また、事前に作成可能なリソースについては、極力事前に作成することによって時間を短縮したりもしました。

メンテナンス日の決定と利用者へのアナウンス

メンテナンス日の決定も、事業側と相談しながら確定していきました。 この日は避けた方がいいなどの多くのコメントを頂きながら最終的には、12月5日の深夜の1:00-6:00の メンテナンスタイムとして、その時間にバージョンアップをすることを決めて、計画を立てました。

2週間前には、パートナーのお客さまやゲストに通知を出してあとは実行するのみとなりました。

本番環境のデータベースのバージョンアップ

本番環境のバージョンアップは、私を含めてSREのメンバー3人が立ち会って実施していきました。 Aurora MySQLのバージョンアは、5.6を利用していたために、内部的には、2段階のバージョンアップが必要でした。 5.6→5.7へのバージョンアップは、当初のシミュレーションの20分程度を予想してましたが、実際には、40分程度かかってしまい、ちょっと焦りましたが、 その後は、予定通りに完了して、なんとかバッファの時間内に完了することができました。 データベースのバージョンアップにかかる時間は、AWSとしては、何も保証してない部分のために、計画時には、あらかじめある程度のバッファを設けて計画をした方がよさそうです。 また、計画策定時においても、リミットを設けてこの時間までに完了しない場合には、バージョンアップを中止するなどの判断基準も事前に立てておいた方がよさそうです。

本番環境の一定期間の重点監視

SRE側の作業は、深夜の1時から実施でしたが、午前4時には、各部門から開発サイドも待機してもらい、バージョンアップ後の動作確認や一定期間の監視など開発全体で 監視を実施しました。Google Meetでみんなで集まりながら、つなげっぱなしの状態で皆で監視体制を敷いてました。

その後、メンテナンスモードを開けて、監視ツールによる重点監視が始まりました。弊社では監視ツールにはDatadogを利用しています。 Datadogをどのように使っているかについては、また後日書いてみようかと思います。

レイテンシのトレンド変化なども確認して、日中帯に問題になりそうな箇所がないかどうか入念に確認してました。

実際に発生した問題

以上が、バージョンアップに関する大きな流れですが、いくつか課題が色々と出てきながらの実施でした。 我々が、この過程で出会った問題をいくつかピックアップしてご紹介したいと思います。

バージョンアップの時間が想定よりも長い

バージョンアップにかかる時間の検証時に、5.6から5.7へのバージョンアップに4時間程度かかってしまうというケースがありました。 同じインスタンスに対しても、取得したSNAPSHOTの時間によって時間がかかるケースとかからないケースがあり、早く終わる時は10分適度で完了するケースもあれば、 3時間程度かかるケースもありました。データベースに入っているデータ量はほぼ同じだったので、どういう条件で遅くなるかを調査することになりました。

色々切り分けた結果、バッチ処理などで長いトランザクション発生中に取得したSNAPSHOTを利用してデータベースをバージョンアップすると長くなる傾向があるようで、 下記のようなメッセージの部分でとても多くの時間を費やしてしまっていました。

 Upgrade in progress: Purging undo records for old row versions. Records remaining: 22

結論としては、事前にバッチ処理を全部止めてバージョンアップを実施すると言う方向になりました。 バッチ処理を止めるという部分については、アプリケーション開発の方とも協力しながら止めて、本番当日は、許容範囲の時間内にバージョンアップを終えることができました。

PostgreSQLのANALYZEの実行漏れによるパフォーマンス劣化

PostgreSQLでは、バージョンアップ後に統計情報が維持されない仕様になってます。 そのため、バージョンアップ完了後に、ANALYZEを実施する必要があります。

 ANALYZE VERBOSE

AWSは、バージョンアップに必要な手順をあらためてまとめるページがあるので、よく読んで、手順書に組み込むことが大切です。 こういうドキュメントがきちんと揃っているのがAWSの良い点だと感じます。 docs.aws.amazon.com

データベースのデフォルトCollationが変わってしまう問題

こちらは、AuroraMySQLのお話です。AuroraMySQL8.0にバージョンアップすると、データベースのColaltionがutf8mb4_0900_ai_ciに書き変わってしまいました。 下記のコマンドで確認できるもののことです。

 SELECT SCHEMA_NAME,DEFAULT_CHARACTER_SET_NAME,DEFAULT_COLLATION_NAME
     FROM INFORMATION_SCHEMA.SCHEMATA;

こちらも手順に組み込み、指定したCollationに変更されるように組み込むことにより解決しました。

ALTER DATABASE [databaseName] CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

SQLが応答を返さない問題

MySQL8.0に更新後、多くのテーブルを結合している一部のSQLが応答しない問題が発生しました。 このSQLの場合には、実行計画を取得するSQLも応答しないという状況になりました。

アソビューでは、パラメータのoptimizer_search_depthを0にするという対応を実施することによって解決しました。 0というのは、実行計画の深さをオプティマイザに任せるという設定になります。詳細は、公式のページをご確認ください。

dev.mysql.com

一時テーブルの領域が足りず実行できない問題

サブクエリやGroup byを用いたSQLは、MySQLでは、一時テーブルの領域を利用します。 MySQL8.0にて、一時テーブルの内部処理が大幅に変更された関係で、バッチなど大きなデータを扱うSQLについては、このエラーが発生してしまいました。 こちらの関連のパラメータとして、temptable_max_mmapというのがあります。 これは、一時テーブルを扱う際に、どのサイズまで扱えるようにするかという上限値を設定するものになります。

アソビューでは、負荷の高いSQLを実行するインスタンスは、通常のReaderインスタンスとは別に立てており、Custom endpointを使って分離されるようにしています。 今回は、その負荷の大きいクエリ用のインスタンスに対して、temptable_max_mmapのデフォルトは1G程度ですが、10倍の10G程度に拡大して 運用することにして解決しました。

GROUP BYの挙動の変化

MySQL5.6では、GROUP BYがORDER BYを兼ねるみたいな仕様がありました。ORDER BY句をきちんとしていてなかったSQLのソート順が変更されてしまうという問題もありました。

5.7時点では、下記のような記述でした。

GROUP BY implicitly sorts by default (that is, in the absence of ASC or DESC designators), but relying on implicit GROUP BY sorting in MySQL 5.7 is deprecated.

これが、8.0においては下記のように変更されました。

GROUP BY 句の非推奨の ASC 修飾子または DESC 修飾子は削除されます。 以前に GROUP BY ソートに依存していたクエリーでは、以前の MySQL バージョンとは異なる結果が生成される場合があります。 特定のソート順序を生成するには、ORDER BY 句を指定します。

こちらも、ORDER BYを明言するように修正することで対応しました。

参考:

https://dev.mysql.com/doc/refman/5.7/en/mysql-nutshell.html#mysql-nutshell-deprecations

https://dev.mysql.com/doc/refman/8.0/ja/mysql-nutshell.html#mysql-nutshell-deprecations

パラメータグループが効かない問題

AuroraMySQLのインプレースによるバージョンアップにおいては、下記の注意書きがあります。

アップグレードプロセス中にカスタムパラメータグループを指定した場合は、アップグレード終了後にクラスターを手動で再起動してください。再起動すると、クラスターがカスタムパラメータ設定の使用をスタートできます。

参考: Amazon Aurora MySQL DB クラスターのメジャーバージョンのアップグレード - Amazon Aurora

バージョンアップのプロセスの中に組み込んでもらいたいという気もしますが、こういう仕様も存在するので実際に、インプレースでバージョンアップする場合には、再起動するプロセスを手順に組み込んでおくことが大切です。

バージョンアップしてみてその後の経過

内部的には大きな変更になり、バージョンアップ後に、パフォーマンスの劣化がみれらる部分はあったもののメインのほとんどの機能は継続的に提供できる形で バージョンアップをすることができました。 これも、社員全員で一丸となって、バージョンアップに取り組んだ成果だと思います。

最後に

今回は、アソビューのSREチームで、最近実施した、データベースのバージョンアップの仕事について書いてみました。 アソビューのSRE一部の仕事ですが、少しでも理解を深まったなら嬉しいです。 アソビューではSREエンジニアを募集しております。 少しでも興味を持っていただき、一緒に働きたいと感じましたら、カジュアルにお話しだけでもできるのでご応募お待ちしております!

www.asoview.com