Aurora Blue/Green Deploymentsによるダウンタイムを最小限に抑えたメジャーアップグレードの実現

Aurora Blue/Green Deploymentsによるダウンタイムを最小限に抑えたメジャーアップグレードの実現

はじめに

こんにちは、SRE部プラットフォームSREブロックの石田です。普段はZOZOTOWNのSREを担当しています。

Amazon Aurora MySQL(以降、Aurora MySQL)のv2系の標準サポートが2024年10月31日に終了しました。私たちのチームではZOZOTOWNのID基盤で使用するAurora MySQLをv2系からv3系へアップグレードしました。ユーザ影響を抑えたアップグレードの実現のため、Amazon Aurora Blue/Green Deployments(以降、Blue/Green Deployment)を社内で初めて採用しました。

本記事では、Blue/Green Deploymentを採用する上で直面した課題や、検証方法について具体的な内容をご紹介します。なお、本記事の内容は2024年10月9日時点の情報に基づいています。

目次

Amazon Aurora Blue/Green Deployments とは

この機能では、稼働中の環境(Blue環境)をもとに論理レプリケーションされた環境(Green環境)を作成できます。これにより稼働中の環境には影響を与えずに、Green環境でデータベースのバージョンアップやパラメータの変更が可能です。準備が整えば、Green環境を新しい稼働環境として昇格させることで、通常1分未満のダウンタイムで安全かつスムーズに移行できます。詳細な仕様や制約、考慮事項については、AWSの公式ドキュメントをご確認ください。

背景・課題

Aurora MySQLのマイナーアップグレードにおいてはIn-placeアップグレードを採用していました。その際のダウンタイムは1分程度でしたが、今回のメジャーアップグレードにおいて検証した結果、10分程度のダウンタイムが発生する可能性を確認しました。ZOZOTOWNの本番環境において、ID基盤の機能が10分も停止することは、ユーザに大きな影響を与えることになります。そのため、ダウンタイムを最小限に抑える手段としてBlue/Green Deploymentの採用を検討しました。

しかし、Blue/Green Deploymentは制限事項に記載されている通り、CloudFormationに対応していません。このため、CloudFormationで管理しているAurora MySQLのバージョン管理に課題がありました。そこで、Blue/Green Deploymentの検証を通して、CloudFormationによるバージョン管理についても確認することにしました。

アップグレードバージョンの決定

はじめに、Aurora MySQL v2系からv3系にアップグレードするバージョンを決定します。ID基盤のAurora MySQLは5.7.mysql_aurora.2.11.5のバージョンを使用しており、アップグレードできるバージョンを下記コマンドで確認します。

-> % aws rds describe-db-engine-versions  --engine aurora-mysql --engine-version 5.7.mysql_aurora.2.11.5 --query 'DBEngineVersions[].ValidUpgradeTarget[].EngineVersion'
[
    "5.7.mysql_aurora.2.11.6",
    "5.7.mysql_aurora.2.12.0",
    "5.7.mysql_aurora.2.12.1",
    "5.7.mysql_aurora.2.12.2",
    "5.7.mysql_aurora.2.12.3",
    "8.0.mysql_aurora.3.03.1",
    "8.0.mysql_aurora.3.03.2",
    "8.0.mysql_aurora.3.03.3",
    "8.0.mysql_aurora.3.04.0",
    "8.0.mysql_aurora.3.04.1",
    "8.0.mysql_aurora.3.04.2",
    "8.0.mysql_aurora.3.04.3",
    "8.0.mysql_aurora.3.05.2",
    "8.0.mysql_aurora.3.06.0",
    "8.0.mysql_aurora.3.06.1",
    "8.0.mysql_aurora.3.07.1"
]

弊チームでは長期サポート(LTS)が提供されるバージョンの採用を方針としています。当時のLTSバージョンである3.04.*の中から、最新の8.0.mysql_aurora.3.04.3を選定しました。最新のLTSバージョンについてはAWSの公式ドキュメントをご確認ください。

なお、以前は2.07.9を使用していましたが、このバージョンから直接v3系へのアップグレードはできませんでした。そのため、まず2.11.5へマイナーバージョンアップを実施し、その後に今回のv3系へのアップグレードを行っています。このように、直接アップグレードができない場合もあるため、事前にアップグレード可能なバージョンを確認しておくことが重要です。サポート期限が迫る前に計画的に対応することで、余裕を持ったアップグレードが可能になります。

Blue/Green Deploymentによるアップグレード検証

ここからはBlue/Green Deploymentによるアップグレード検証の手順をご紹介します。

アップグレード手順の検証

まずはアップグレードの手順を検証するため、CloudFormationで検証用のAuroraクラスターを作成し、想定通りにアップグレードが行えるかを確認します。また、切り戻しが可能かどうかも併せて確認します。

1. 検証用のAuroraクラスター作成

開発環境で使用しているCloudFromationテンプレートを参考にして、Aurora MySQL v2系のクラスターを作成します。下記に作成したテンプレートを記載します。必要なパラメータがわかりやすいように関連のないParametersやResourcesの記載は省略しています。

---
AWSTemplateFormatVersion: "2010-09-09"
Description: "[upgrade-test] Aurora"
Parameters:
  GlobalPrefix:
    Type: String
    Default: upgrade-test
  GlobalEnvironment:
    Type: String
    Default: dev
  ServiceName:
    Type: String
    Default: upgrade-test
  RDSEngine:
    Type: String
    Default: aurora-mysql
  RDSEngineVersion:
    Type: String
    Default: 5.7.mysql_aurora.2.11.5
  RDSParameterGroupFamily:
    Type: String
    Default: aurora-mysql5.7

Resources:
  DBClusterParameterGroupZozoID:
    Type: "AWS::RDS::DBClusterParameterGroup"
    Properties:
      Description: !Sub "cluster parameter group for ${ServiceName}"
      Family: !Ref RDSParameterGroupFamily
      Parameters:
        binlog_format: ROW

  DBParameterGroupZozoID:
    Type: "AWS::RDS::DBParameterGroup"
    Properties:
      Description: !Sub "parameter group for ${ServiceName}"
      Family: !Ref RDSParameterGroupFamily

  DBClusterZozoID:
    Type: "AWS::RDS::DBCluster"
    Properties:
      DBClusterIdentifier: !Sub ${GlobalEnvironment}-${GlobalPrefix}-${ServiceName}
      DatabaseName: !Ref DBDatabaseName
      DBClusterParameterGroupName: !Ref DBClusterParameterGroupZozoID
      Engine: !Ref RDSEngine
      EngineVersion: !Ref RDSEngineVersion

  DBInstanceZozoID:
    Type: "AWS::RDS::DBInstance"
    Properties:
      DBClusterIdentifier: !Ref DBClusterZozoID
      DBInstanceClass: !Ref Instance1DBClass
      DBParameterGroupName: !Ref DBParameterGroupZozoID
      Engine: !Ref RDSEngine

  DBInstanceZozoIDSecond:
    Type: "AWS::RDS::DBInstance"
    Properties:
      DBClusterIdentifier: !Ref DBClusterZozoID
      DBInstanceClass: !Ref Instance2DBClass
      DBParameterGroupName: !Ref DBParameterGroupZozoID
      Engine: !Ref RDSEngine
注意点

Blue/Green DeploymentではBlue環境からGreen環境にレプリケーションするため、バイナリログを使用しています。そのため、実際の稼働環境では、事前にクラスターのDBパラメータグループのバイナリログ(binlog_format)を有効にする必要がある点ご注意ください。なお、複製の不整合のリスクを減らすためにROWの設定が推奨されています。詳細はAWSの公式ドキュメントをご確認ください。

2. 新バージョンのDBパラメータグループ作成

1で作成したテンプレートに下記を追加して、Aurora MySQL v3系に対応したDBパラメータグループを作成します。作成したDBパラメータグループは次の手順で使用します。

---
AWSTemplateFormatVersion: "2010-09-09"
Description: "[upgrade-test] Aurora"
Parameters:
  ServiceName:
    Type: String
    Default: upgrade-test
  RDSParameterGroupFamilyMySQL80:
    Type: String
    Default: aurora-mysql8.0

Resources:
  DBClusterParameterGroupMySql80ZozoID:
    Type: "AWS::RDS::DBClusterParameterGroup"
    Properties:
      Description: !Sub "cluster parameter group for ${ServiceName}"
      Family: !Ref RDSParameterGroupFamilyMySQL80
      Parameters:
        binlog_format: ROW

  DBParameterGroupMySql80ZozoID:
    Type: "AWS::RDS::DBParameterGroup"
    Properties:
      Description: !Sub "parameter group for ${ServiceName}"
      Family: !Ref RDSParameterGroupFamilyMySQL80

3. Blue/Green Deploymentによるアップグレードを実施

前述した通りBlue/Green DeploymentはCloudFormationに対応していないため手動で作成します。Blue/Green Deploymentを作成する際、Green環境は8.0.mysql_aurora.3.04.3のバージョンで作成します。DBパラメータグループは2で作成したものを指定します。作成方法はAWSの公式ドキュメントをご確認ください。

Blue/Green Deploymentが作成されると8.0.mysql_aurora.3.04.3の新バージョンでGreen環境が作成されます。

Blue/Green Deploymentの切り替え

切り替えを実行し、新バージョンに切り替わることを確認します。

Blue/Green Deploymentの切り替え

4. 再びCloudFormationの管理化

アップグレード後、CloudFormationで管理しているリソースに差分が生じるため、テンプレートを修正して再適用します。ただし、本来CloudFormation管理下のリソースは、スタック外で変更することを推奨しておらず、CloudFormationとして動作を保証していない点ご留意ください。詳細はAWSの公式ドキュメントをご確認ください。

以下に修正後のテンプレートを記載します。変更した箇所にコメントを追加しています。

---
AWSTemplateFormatVersion: "2010-09-09"
Description: "[upgrade-test] Aurora"
Parameters:
  GlobalPrefix:
    Type: String
    Default: upgrade-test
  GlobalEnvironment:
    Type: String
    Default: dev
  ServiceName:
    Type: String
    Default: upgrade-test
  RDSEngine:
    Type: String
    Default: aurora-mysql
  RDSEngineVersion:
    Type: String
    Default: 8.0.mysql_aurora.3.04.3 # 新バージョンに変更
  RDSParameterGroupFamilyMySQL80:
    Type: String
    Default: aurora-mysql8.0

Resources:
  DBClusterParameterGroupMySql80ZozoID:
    Type: "AWS::RDS::DBClusterParameterGroup"
    Properties:
      Description: !Sub "cluster parameter group for ${ServiceName}"
      Family: !Ref RDSParameterGroupFamilyMySQL80
      Parameters:
        binlog_format: ROW

  DBParameterGroupMySql80ZozoID:
    Type: "AWS::RDS::DBParameterGroup"
    Properties:
      Description: !Sub "parameter group for ${ServiceName}"
      Family: !Ref RDSParameterGroupFamilyMySQL80

  DBClusterZozoID:
    Type: "AWS::RDS::DBCluster"
    Properties:
      DBClusterIdentifier: !Sub ${GlobalEnvironment}-${GlobalPrefix}-${ServiceName}
      DatabaseName: !Ref DBDatabaseName
      DBClusterParameterGroupName: !Ref DBClusterParameterGroupMySql80ZozoID # 新しいDBパラメータグループに変更
      Engine: !Ref RDSEngine
      EngineVersion: !Ref RDSEngineVersion

  DBInstanceZozoID:
    Type: "AWS::RDS::DBInstance"
    Properties:
      DBClusterIdentifier: !Ref DBClusterZozoID
      DBInstanceClass: !Ref Instance1DBClass
      DBParameterGroupName: !Ref DBParameterGroupMySql80ZozoID # 新しいDBパラメータグループに変更
      Engine: !Ref RDSEngine

  DBInstanceZozoIDSecond:
    Type: "AWS::RDS::DBInstance"
    Properties:
      DBClusterIdentifier: !Ref DBClusterZozoID
      DBInstanceClass: !Ref Instance2DBClass
      DBParameterGroupName: !Ref DBParameterGroupMySql80ZozoID # 新しいDBパラメータグループに変更
      Engine: !Ref RDSEngine

変更セットを作成し、CloudFormationのコンソールよりプロパティレベルの変更の詳細を確認すると以下のような差分が確認できます。

クラスターのプロパティレベルの変更の詳細

インスタンスのプロパティレベルの変更の詳細

CloudFormation上は差分がある状態ですが、このテンプレートを適用することで問題なくCloudFormation管理下に戻すことができました。

なお、テンプレート適用後、ライターインスタンスのイベントログにFinished updating DB parameter groupというメッセージが表示されていました。DBパラメータグループの更新が完了したというメッセージになりますが、このメッセージが出力されたからといって、DBパラメータグループの設定内容が実際に更新されたわけではありませんでした。

AWSサポートに問い合わせたところ、ログが検出された原因の特定はできませんでしたが、現在使用されているDBパラメータグループに再度変更するようなAPI呼び出しは実行可能とのことでした。また、変更前に違うDBパラメータグループが適用されていたことやパラメータが実際に変更されたことを直ちに示すものではないとのことです。ただし、テンプレート適用前後で、DBパラメータグループの設定内容に変更がないか確認しておくと安心です。

注意点

テンプレート適用前にインスタンスのDBパラメータグループのステータスを確認してください。ステータスがpending-rebootの場合はテンプレート適用時に再起動する可能性があります。ステータスが同期中であれば再起動が発生することはありません。

5. 切り戻し

Blue/Green Deploymentには自動的な切り戻し機能はありません。Blue/Green Deployment作成時にはBlue環境からGreen環境にレプリケーションされますが、切り替えたタイミングでレプリケーションは切断されます。そのため、切り戻しは手動でエンドポイントを操作し、新バージョンのクラスターエンドポイントを別の名前に変更後、旧バージョンのクラスターエンドポイントを元に戻す流れで行います。イメージ図のクラスタ名およびインスタンス名はわかりやすくするために簡略化しています。

  1. Blue/Green Deploymentの削除
    まず、Blue/Green Deploymentを削除します。これにより、新バージョンと旧バージョンのクラスターの紐付きが解消されます。 Blue/Green Deploymentを削除した状態

  2. 新バージョンのクラスター名を変更
    新バージョンのクラスター名を別の名前に変更します。ここでは末尾に-newをつけます。これによりエンドポイントが変更されるため、リクエストが全断します。 新バージョンのクラスター名を変更した状態

  3. 新バージョンのインスタンス名を変更
    新バージョンのクラスター名の変更が完了したら、新バージョンのインスタンス名も別の名前に変更します。ここでは末尾に-newをつけます。 新バージョンのインスタンス名を変更した状態

  4. 旧バージョンのインスタンス名を変更
    次に、旧バージョンのインスタンス名を正規の名前に変更します。 旧バージョンのインスタンス名を変した状態

  5. 旧バージョンのクラスター名を変更
    最後に、旧バージョンのクラスター名を正規の名前に変更します。この変更が完了するとエンドポイントが元に戻ります。そして、旧バージョンのクラスターに対してリクエストが届くようになります。 旧バージョンのクラスター名を変更した状態

こちらの手順で実施し、15分ほどで問題なく切り戻すことができました。

注意点

本番環境での実施時には、アップグレード中に問題が発生した場合、データに不整合が生じているかどうかの懸念があります。例えば、部分的なINSERT処理が失敗するなどの不具合が考えられます。そのため、切り戻し後にはデータの整合性を確認し、補正が必要となる場合があります。

API利用確認

開発環境のアップグレードを実施し、新バージョンのAurora MySQLにてID基盤で使用しているAPIが問題なく動作することを確認します。アップグレードは前述の通りの手順で実施します。結果としてアップグレードは問題なく完了し、ID基盤で使用しているAPIも正常に動作しました。

検証環境のアップグレード

検証環境のアップグレードは、商用相当のリクエスト負荷をかけて実施し、エラー発生状況やダウンタイムを確認します。商用相当のリクエストをかける理由は、切り替えのベストプラクティスで記載されている通り、切り替え時のダウンタイムはリクエスト量に依存するためです。また、負荷をかけるツールは弊チームで開発したOSSツールであるGatling Operatorを使用しています。詳細は以前TECH BLOGに公開された下記記事をご参照ください。

techblog.zozo.com

アップグレードは前述の通りの手順で実施します。結果としては想定通りのエラーが発生し、ダウンタイムとしては1分程度でした。なお、ダウンタイムの計測には、Datadog APMのトレース機能を利用しています。アプリケーションエラーを示すtrace.http.request.errorsメトリクスを可視化することでエラーが発生していた時間を計測しています。以下はDatadog Dashboard上で可視化したグラフです。これより、エラーの発生時間が1分程度であったことを確認できます。

検証環境のダウンタイム

検証結果

ここまでの検証を通して、以下の点を確認できました。

  • Blue/Green Deploymentを利用して、Aurora MySQL v2系からv3系へのアップグレードが可能であること
  • v3系からv2系への切り戻しが可能であること
  • アップグレード後、再びCloudFormationによる管理が可能であること
  • v3系において、ID基盤としてのアプリケーションが問題なく動作すること
  • ダウンタイムは1分程度であり、許容範囲内であること

本番環境のアップグレード

本番環境でのアップグレードは、ユーザへの影響を最小限に抑えるため、早朝の時間帯に実施します。アップグレードは前述の通りの手順で実施します。結果として、検証時の予測通りにエラーが発生し、ダウンタイムも約50秒と想定内に収まりました。これにより、問題なくアップグレードを完了できました。

注意点

Blue/Green Deploymentは新しいクラスターに切り替わるため、バイナリログを使用したデータの連携をしている場合は注意が必要です。実際に、ID基盤のデータベースではGCPのDatastreamを介してBigQueryにデータを連携していますが、この点を見落としていました。

公式ドキュメントコンシューマーの親ノードの更新の項目では、バイナリログコンシューマーがある場合はレプリケーションの継続性を維持するため、切り替え後に親ノードを更新する必要があると記載されています。今回のケースでは、バイナリログコンシューマーがDatastreamにあたります。

切り替え後のライターインスタンスでは、以下のようなバイナリログファイル名(mysql-bin-changelog.000008)と位置(536)を含む情報がイベントログに出力されます。この情報を使用してDatastreamを更新することでデータ連携を再開できます。

ライターインスタンスのイベントログ

この点を見落としていたため、切り替え後にデータ連携が停止し、復旧対応としてbackfill(全量転送)を実施せざるを得ませんでした。こうした事態を防ぐためにも、事前にバイナリログを利用するコンシューマーの存在を確認し、切り替え後に必要となる対応を計画的に準備しておくことが重要です。

まとめ

本記事では、Blue/Green Deploymentによるアップグレードの検証方法や移行に際して直面したコード管理の課題に対する対応について、具体的な取り組みを紹介しました。

入念なアップグレード検証により、ユーザへの影響を最小限に抑えつつ、確実なアップグレードを実現できました。また、CloudFormationで管理しているAmazon Aurora MySQLのバージョン管理においても、スタック外での変更は推奨されないものの、問題なく継続できることを確認できました。

さらに、この取り組みで得られた知見やノウハウは、社内の別マイクロサービスにおけるAuroraのメジャーアップグレードにも活用され、スムーズな移行を支援する結果につながりました。Blue/Green Deploymentによるアップグレードを検討されている方にとって、この記事が参考になれば幸いです。

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

hrmos.co

corp.zozo.com

カテゴリー