ウェブサービスのトラフィックが急増して障害が発生してしまうことはあると思う.そういうときにリクエストを一時的にバッファリングして,適切に入場制限をする仕組みとして「Virtual Waiting Room(仮想待合室)」という仕組みがある.実際にショップ・病院などに行ったときに番号札を受け取って待合室で待つという体験をしたことがあると思う.
Virtual Waiting Room on AWS
AWS ではソリューションとして(サービスではなく)「Virtual Waiting Room on AWS」を提供している.Virtual Waiting Room on AWS をデプロイすると,サービス側に対するトラフィックを「仮想待合室」で制御できる.
AWS 以外で関連するサービスとしては Cloudflare Waiting Room や Queue-it などもある❗️個人的には 018 サポートサイトで Cloudflare Waiting Room・トイザらスサイトで Queue-it が導入されているのを体験したことがある👀
Virtual Waiting Room on AWS 関連サイト
ソリューションサイト以外に Virtual Waiting Room on AWS に関連するサイトとして,ソリューションを詳細に解説した Implementation Guide と Amazon Web Services Blog の記事がある.Virtual Waiting Room on AWS を試す前に一度ザッと読んでおくと良いと思う💡
また GitHub には AWS CloudFormation テンプレート・AWS Lambda 関数のコードなども公開されていて参考になる❗️
さらに @_kensh さんが ServerlessDays Tokyo 2023 で発表された資料「サーバーレスで仮想待合室を作ろう!」で Virtual Waiting Room on AWS が必要になるシチュエーションと実装詳細の解説がまとまってて最高だった👏
Virtual Waiting Room on AWS の動作イメージ
最初に Virtual Waiting Room on AWS の動作イメージを見てもらうとわかりやすくなると思う💡まず,待合室サイトの初期ページにアクセスして,表示されている Reserve ボタンを押すと順番待ちに入れる.
以下のキャプチャは5回ほど待合室サイトにアクセスしたところ.You are number 5 in line と表示されている通り,今は5名待っていることになる.この Waiting Room 画面では My Position や Serving Position など待合室のステータスを確認できる.
今度はコントロールパネル(管理画面)にアクセスする.この画面でも待合室のステータスを確認できる.そして,デフォルトでは Serving Counter 0 になっていて全員ブロックされているため,Increment Serving Counter の Increment by: 100 で Change ボタンを押してサービス側に通す人数制限を緩和する.
すると,待合室サイト側で Waiting for line to advance ボタンが押せるようになり,今度は実際のサービスサイト(今回は EC サイトのモックアップ)にアクセスできる.ザッとこんな感じ❗️
Virtual Waiting Room on AWS をセットアップする
Virtual Waiting Room on AWS をセットアップするときは AWS Solutions Library のサイトにある Launch in the AWS Console
ボタンを押して us-east-1
リージョンに AWS CloudFormation スタックをデプロイすれば OK👌2024年1月20日時点で問題なく動く😃
しかし1点注意点があって,AWS CloudFormation スタック名は短くしておく必要がある.僕は vwr-on-aws
にして動作確認できたので,真似してもらって良いと思う.詳しくは記事の最後に書くけど,最初スタック名を virtual-waiting-room-on-aws
にしたらデプロイエラーになって時間を無駄にした💣
あとコントロールパネルに Amazon API Gateway のエンドポイントを実行するための権限を持ったアクセスキーを設定する必要がある.今回は vwr-on-aws
という名前の IAM User にした.ポリシーは AWS CloudFormation で作られている IAM Group があってそこにアタッチすれば引き継がれる👌Implementation Guide に IAM User を作ると載ってるけど,隅々まで読まないと気付きにくいと思う.
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "execute-api:Invoke" ], "Resource": "arn:aws:execute-api:us-east-1:000000000000:m6y97xvptd/*", "Effect": "Allow" } ] }
AWS CloudFormation スタックは基本機能だと大きく3つのネストスタックに分割されている🧩
- vwr-on-aws
- CoreModuleStack
- AuthorizersModuleStack
- SampleModuleStack
デプロイ時間は「27分ぐらい」だった.特に Amazon ElastiCache クラスタの構築(論理名 RedisReplicationGroup
)に10分ぐらい待たされるため,もしデプロイが進んでいるのか不安になったら Amazon ElastiCache コンソールを確認してみると良いと思う.
2024-01-20 11:34:00 UTC+0900 2024-01-20 12:00:56 UTC+0900
すべてデプロイが終わったら AWS CloudFormation スタックのアウトプットから ControlPanelURL
と WaitingRoomURL
の値を控えておく.既に検証環境は削除していてアクセスできないけど,実際に以下のような URL になっていた📝
# ControlPanelURL https://d1096am4wacsdc.cloudfront.net/control-panel/index.html?eventId=Sample&publicApiUrl=https://d3bxth0af8tkl8.cloudfront.net&privateApiUrl=https://m6y97xvptd.execute-api.us-east-1.amazonaws.com/api®ionName=us-east-1 # WaitingRoomURL https://d1096am4wacsdc.cloudfront.net/waiting-room-site/index.html?eventId=Sample&publicApiUrl=https://d3bxth0af8tkl8.cloudfront.net&commerceApiUrl=https://fv5dbf3ata.execute-api.us-east-1.amazonaws.com/store
アーキテクチャ図
Virtual Waiting Room on AWS のアーキテクチャ図は Implementation Guide に載っている.コンポーネントも多く複雑に感じるけど,optional と書いてある部分を除けば Public and private APIs と書いてある部分が中心になる.
しかし AWS Lambda / Amazon DynamoDB などはあくまで概要レベルのアーキテクチャ図になっていて,詳細も Implementation Guide に載っている.Amazon API Gateway から呼び出される AWS Lambda 関数の多さに驚く👀
Virtual Waiting Room on AWS の仕組みと各コンポーネントの挙動に関しては Implementation Guide の How the solution works と Solution components に詳しく載っている.これらを読みながら実際にデプロイされた AWS リソースの設定などを探っていくのが良いと思う.
個人的に挙動を調査したログを残しておく.まず AssignQueueNum
API は {"api_request_id": "581280c8-79b3-4212-b3eb-7b3e84c9b91f"}
のようなレスポンスを返していて,GetQueueNumber
API は {"queue_number": 2, "entry_time": 1705721798, "event_id": "Sample", "status": 1}
のようなレスポンスを返している💡
また Virtual Waiting Room で待機してるときは GetServingNumber
API と GetWaitingNum
API を定期的に呼び出していて(ポーリングしていて)それぞれ {"waiting_num": 3}
や {"serving_counter": "1"}
のようなレスポンスを返していて,Virtual Waiting Room から次に進めるかどうかを制御している😀DevTools で待機中の API 呼び出しを眺めていると理解しやすいと思う👌
順番が来たら JWT トークンを取得して,サービス側の Amazon API Gateway の認証に使う.Amazon API Gateway の設定を見ると WaitingRoomAuthorizer
という Amazon API Gateway Lambda オーソライザーの設定が見つかる🔑
AWS CloudFormation スタックを削除する
そのままにしておくとコストが発生するため,Virtual Waiting Room on AWS の検証が終わったら AWS CloudFormation スタック vwr-on-aws
を削除する.削除する順番としては「1. IAM User」→「2. AWS CloudFormation スタック」→「3. Amazon S3 バケット(2つ)」で,詳しくは Implementation Guide にすべて書いてある👌
AWS CloudFormation スタック名に注意する
最初 AWS CloudFormation スタック名を virtual-waiting-room-on-aws
にしたらデプロイの後半でエラーになって,ロールバックの時間も含めて1時間ほど無駄にしてしまった.エラーになったのは Amazon EventBridge で「targetId の64文字制限」に該当してしまった.確かに virtual-waiting-room-on-aws-CoreModuleStack-SDAGBI8A4ER1-expiredEvents
は70文字ある💨
Resource handler returned message: "1 validation error detected: Value 'virtual-waiting-room-on-aws-CoreModuleStack-SDAGBI8A4ER1-expiredEvents' at 'targets.1.member.id' failed to satisfy constraint: Member must have length less than or equal to 64 (Service: EventBridge, Status Code: 400, Request ID: 72b173d6-99c8-445c-9755-d0351b64ab19)" (RequestToken: c69baab4-b984-4a92-e37e-75f30dca430d, HandlerErrorCode: GeneralServiceException)
ちなみに AWS CloudFormation テンプレートを読むと,Amazon SQS キュー名は AWS CloudFormation の「カスタムリソース」を使って文字数を制御しているため,同じ仕組みが入っていれば良いのに〜と思った💡
"WaitingRoomQueue": { "Type": "AWS::SQS::Queue", "Properties": { "QueueName": { "Fn::Join": ["-", [ { "Fn::GetAtt": [ "InvokeShortenStackNameLambda", "returnValue" ] }, "WaitingRoomQueue"] ] }, "KmsMasterKeyId": "alias/aws/sqs", "KmsDataKeyReusePeriodSeconds": 300, "RedrivePolicy": { "deadLetterTargetArn" : {"Fn::GetAtt": [ "WaitingRoomDeadLetterQueue", "Arn" ]}, "maxReceiveCount" : 2 }, "VisibilityTimeout" : 30 } },
その他実施ログ
まとめ
「Virtual Waiting Room(仮想待合室)」という仕組みが欲しくなることはあると思う.AWS を活用して実現できるソリューションとして「Virtual Waiting Room on AWS」を実際に試して紹介した❗️それなりに構成は複雑ですべてを理解しようとすると大変だけど,Virtual Waiting Room on AWS にはカスタマイズ性もあって,既存サービスに組み込みやすく作られている👌とは言え,あくまで個人的にはソリューションではなく「マネージドサービスとして」提供されたらもっと良いのにな〜と思ったりはする💨
ということで今回は Virtual Waiting Room on AWS の紹介でした \( 'ω')/