はじめに
GMOコネクトの野尻です。
今回、数万rpsという高負荷に対応可能なAWS環境を構築する機会があり、その設計・構築内容について本記事にまとめました。
環境構築の前提条件
今回構築した環境の前提条件は以下の通りです:
-
性能要件は数万rps(requests per sec)
- 平常時は1,000rps程度だが数分で数万rpsまで増加(リクエストが数分で数十倍になるという、非常に厳しいスパイクへの性能要求)
-
さらに今後、性能要件が増えていくことを考慮して拡張性のある構成とする
- 事前調査により、DBのデータを処理するデータアクセス層がボトルネックになることが判明済み
-
CloudFormationを使って構築
- 効率性、メンテナンス性を考慮して、作成するテンプレートはなるべく各リージョン両方で流用可能なものを作成
設計した環境構成
環境構成図
※実際の環境にはNLB(Network Load Balancer)やVPC Endpointなどが含まれていますが、今回は記事の説明に関わるリソース部分を抜粋して記載しています。
構成の特徴
マルチリージョン構成
- 東京/大阪の両リージョンとも通常稼働させるACT/ACT(アクティブ/アクティブ)構成
ロジック層の処理フロー
ロジック層のECS(Fargate)からはリクエスト元に合わせて、どのリージョンのデータアクセス層を利用するか判別してリクエストをさばきます。
ざっくりロジックを説明すると:
- リクエストには識別子が含まれており、この識別子とリクエスト先のデータアクセス層のマッピング情報をDynamoDBに格納
- ロジック層のECS(Fargate)は初回リクエスト時にDynamoDBに上記情報を書き込み
- 次回以降のリクエスト時にDynamoDBから上記情報を参照し、目的のデータアクセス層へとリクエストを投げる
拡張性への対応
- 性能を拡張する場合は、VPC(データアクセス層)を増設することで対応
Aurora Global Databaseを採用しなかった理由
AWSに詳しく勘のいい人は「Aurora Global Databaseを使えばリージョン間でデータ同期されるので、わざわざリージョン跨ぎでデータにアクセスするようなロジックを組み込む必要は無いのでは?」と思われることでしょう。
今回、以下の理由からAurora Global Databaseの採用は見送っています:
-
性能要件に対してDBの書き込みスペック、リージョン間の同期遅延による影響が無視できない
- 今回、一つのシナリオで2種類のAPI(DB書き込み有り)が連続で呼び出される
- この際、一つ目のAPIで東京リージョンのDBにアクセスがいき、二つ目のAPIで大阪リージョンのDBにアクセスがいったときに同期遅延が発生しているとエラーが発生する
- 今回は数万rpsをさばく必要があり、この性能要件に対応可能か不透明なところがあった
- 今回、一つのシナリオで2種類のAPI(DB書き込み有り)が連続で呼び出される
-
今後増加していく性能要件に対応していくことを考慮すると、Aurora Global Databaseのみの利用ではいずれ限界がくる
- 今回設計した構成ならば、(理論上は)VPC(データアクセス層)を増設していくことで性能要件の増加に対応し続けることが可能
※DynamoDBはGlobal Tablesを利用していますが、こちらは書き込み/読み取りスペックを数万rpsに設定することが可能で、これにより同期遅延がほぼ無いためです。
(万が一同期遅延が発生して目的のレコードが見つからなかったときに備えてレコード検索のリトライ処理も組み込み)
構築時に検討が必要だった課題
AWSアカウント内で一意なリソースのCloudFormationテンプレート内での参照
IAMロールなどAWSアカウント内で一意なリソースがあるが、CloudFormation内のRef参照はリージョンを跨いで利用できない:
- 作成するリソースに命名規則を設定し、これを利用した参照形式でCloudFormationのテンプレートを記載
Cross VPC Peeringの設定
別リージョンへのルーティング設定はCIDR指定となるため、以下の点に注意が必要:
-
各リージョン、各VPCのCIDRで重複を発生させない設計が必須
- VPC(データアクセス層)が今後増設されていくことも考慮してCIDRの設計が必要
-
適宜リージョンを切り替えながらCloudFormationのテンプレートを適用していく必要あり
- 「東京リージョンでVPC Peeringを作成、次は大阪リージョンでVPC Peeringを作成、その後それぞれのリージョンでルーティング設定追加して、このとき使うCIDRは・・・」といった具合に参照するリソースとスタックを作成するリージョンが切り替わっていくため、構築手順がなかなか複雑に。
- 手間に感じるかもしれませんが、操作対象のリージョン情報を含めた構築手順をドキュメントに整理しておくことは必須だと思います。
非常に厳しいスパイクへの性能要求対応
ECSはAutoScalingでタスク数を増加してくれますが、リクエストが数分で数十倍になるレベルのスパイク対応は厳しいものがありました。
こちらについては参考の記事で紹介されている仕組みを採用して対応しており、スパイク対応にお困りの方はご参考までに。
まとめ
本記事では、数万rpsという高負荷に対応可能なAWS環境の構築について解説しました。
主なポイント:
-
マルチリージョンACT/ACT構成の採用
- 東京・大阪リージョンでの冗長化により高可用性を実現
- リージョンを跨いだVPC(データアクセス層)の活用
-
拡張性を重視した設計
- VPC(データアクセス層)の増設による性能拡張が可能
- Aurora Global Databaseではなく独自のデータアクセス層設計を採用
-
CloudFormationによるIaC実装
- 各リージョンで流用可能なテンプレート設計
- Cross VPC Peeringの複雑な構築手順への対応
-
厳しいスパイク要求への対応
- 数分で数十倍になるトラフィック増加に対応する仕組みの実装
この構成により現在の性能要件を満たしつつ、将来的な性能要件の増加にも柔軟に対応できるスケーラブルなインフラを構築することができました。
弊社では、AWSを使ったサービスの開発や技術支援をはじめ、幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。
お問合せ: https://gmo-connect.jp/contactus/