kakakakakku blog

Weekly Tech Blog: Keep on Learning!

トラフィックの急増に耐えられるソリューション!? Virtual Waiting Room on AWS を試した

ウェブサービスのトラフィックが急増して障害が発生してしまうことはあると思う.そういうときにリクエストを一時的にバッファリングして,適切に入場制限をする仕組みとして「Virtual Waiting Room(仮想待合室)」という仕組みがある.実際にショップ・病院などに行ったときに番号札を受け取って待合室で待つという体験をしたことがあると思う.

Virtual Waiting Room on AWS

AWS ではソリューションとして(サービスではなく)「Virtual Waiting Room on AWS」を提供している.Virtual Waiting Room on AWS をデプロイすると,サービス側に対するトラフィックを「仮想待合室」で制御できる.

AWS 以外で関連するサービスとしては Cloudflare Waiting RoomQueue-it などもある❗️個人的には 018 サポートサイトで Cloudflare Waiting Room・トイザらスサイトで Queue-it が導入されているのを体験したことがある👀

aws.amazon.com

Virtual Waiting Room on AWS 関連サイト

ソリューションサイト以外に Virtual Waiting Room on AWS に関連するサイトとして,ソリューションを詳細に解説した Implementation Guide と Amazon Web Services Blog の記事がある.Virtual Waiting Room on AWS を試す前に一度ザッと読んでおくと良いと思う💡

docs.aws.amazon.com

aws.amazon.com

また GitHub には AWS CloudFormation テンプレート・AWS Lambda 関数のコードなども公開されていて参考になる❗️

github.com

さらに @_kensh さんが ServerlessDays Tokyo 2023 で発表された資料「サーバーレスで仮想待合室を作ろう!」で Virtual Waiting Room on AWS が必要になるシチュエーションと実装詳細の解説がまとまってて最高だった👏

speakerdeck.com

Virtual Waiting Room on AWS の動作イメージ

最初に Virtual Waiting Room on AWS の動作イメージを見てもらうとわかりやすくなると思う💡まず,待合室サイトの初期ページにアクセスして,表示されている Reserve ボタンを押すと順番待ちに入れる.

待合室サイトの初期ページにアクセスする

以下のキャプチャは5回ほど待合室サイトにアクセスしたところ.You are number 5 in line と表示されている通り,今は5名待っていることになる.この Waiting Room 画面では My PositionServing Position など待合室のステータスを確認できる.

待合室サイトで待つ

今度はコントロールパネル(管理画面)にアクセスする.この画面でも待合室のステータスを確認できる.そして,デフォルトでは Serving Counter 0 になっていて全員ブロックされているため,Increment Serving CounterIncrement by: 100Change ボタンを押してサービス側に通す人数制限を緩和する.

コントロールパネルにアクセスする

すると,待合室サイト側で Waiting for line to advance ボタンが押せるようになり,今度は実際のサービスサイト(今回は EC サイトのモックアップ)にアクセスできる.ザッとこんな感じ❗️

サービスサイトにアクセスする

Purchase now ボタンを押して購入操作を試す

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 にしたらデプロイエラーになって時間を無駄にした💣

aws.amazon.com

あとコントロールパネルに 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"
        }
    ]
}

docs.aws.amazon.com

AWS CloudFormation スタックは基本機能だと大きく3つのネストスタックに分割されている🧩

  • vwr-on-aws
    • CoreModuleStack
    • AuthorizersModuleStack
    • SampleModuleStack

AWS CloudFormation スタック一覧

デプロイ時間は「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 スタックのアウトプットから ControlPanelURLWaitingRoomURL の値を控えておく.既に検証環境は削除していてアクセスできないけど,実際に以下のような 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&regionName=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 と書いてある部分が中心になる.

Architecture overview - Virtual Waiting Room on AWS より引用

しかし AWS Lambda / Amazon DynamoDB などはあくまで概要レベルのアーキテクチャ図になっていて,詳細も Implementation Guide に載っている.Amazon API Gateway から呼び出される AWS Lambda 関数の多さに驚く👀

Solution components - Virtual Waiting Room on AWS より引用

Virtual Waiting Room on AWS の仕組みと各コンポーネントの挙動に関しては Implementation Guide の How the solution worksSolution components に詳しく載っている.これらを読みながら実際にデプロイされた AWS リソースの設定などを探っていくのが良いと思う.

docs.aws.amazon.com

docs.aws.amazon.com

個人的に挙動を調査したログを残しておく.まず 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 呼び出しを眺めていると理解しやすいと思う👌

待機中の API 呼び出し

順番が来たら JWT トークンを取得して,サービス側の Amazon API Gateway の認証に使う.Amazon API Gateway の設定を見ると WaitingRoomAuthorizer という Amazon API Gateway Lambda オーソライザーの設定が見つかる🔑

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 にすべて書いてある👌

docs.aws.amazon.com

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
    }
},

その他実施ログ

AWS Lambda 関数は計23種類ある

Amazon DynamoDB テーブル QueuePositionEntryTimeTable のデータ例

まとめ

「Virtual Waiting Room(仮想待合室)」という仕組みが欲しくなることはあると思う.AWS を活用して実現できるソリューションとして「Virtual Waiting Room on AWS」を実際に試して紹介した❗️それなりに構成は複雑ですべてを理解しようとすると大変だけど,Virtual Waiting Room on AWS にはカスタマイズ性もあって,既存サービスに組み込みやすく作られている👌とは言え,あくまで個人的にはソリューションではなく「マネージドサービスとして」提供されたらもっと良いのにな〜と思ったりはする💨

ということで今回は Virtual Waiting Room on AWS の紹介でした \( 'ω')/