Lambda Web Functionsをどう選ぶか
注文APIを題材に、再試行、DB接続、HTTPの入口、更新失敗からの復旧をAWSで比べます。通常のLambdaとの対照から、Web Functionsを選ぶ条件を考えます。
Web Functionsを選ぶ基準
Lambda Web Functionsを選ぶなら、HTTPの入口、DB接続、失敗した後の扱いを一緒に考えます。今回の検証では、直接アクセスとHTTP API経由で、受け付けた件数が分かれました。注文の再送や、失敗した更新からの復旧も、アプリ側で設計が必要でした。
通常のLambdaであるEvent Functionsとも比べます。こちらは、呼び出し1回ごとにhandlerが実行される方式です。Event Functionsの同時処理 では、1つの実行環境が同時に1件を処理します。Web Functionsは、起動したHTTPサーバーへリクエストを渡します。Honoは、HTTPの処理を書くWeb frameworkです。今回のEvent Functionsには、呼び出し形式とHonoをつなぐadapterを加えました。
選ぶ基準は、「同じ実行環境で何件を同時に処理したか」だけでは足りません。注文の完了条件、DB接続数、HTTPの入口、更新の戻し方を、同じ業務処理で確かめます。
注文APIで比べる
注文IDをDBへ保存し、結果を返す小さなAPIを用意しました。決済や在庫更新は含めていません。保存処理はWeb Functions、Event Functions、SQSのworkerで共通にしています。

青線は呼び出しとDB接続です。Web FunctionsはVPC接続用のNetworkConnectorを通して、外部公開していないAuroraへ接続します。Event FunctionsもVPCへ接続します。灰色の破線は、Web FunctionsのログをCloudWatch Logsへ送る経路です。呼び出し元への応答は、呼び出しの経路を戻ります。代表的な処理経路を描いており、Secrets Manager、S3、Event Functions・受付Lambda・workerのログ経路は省略しています。
Runtimeは、プログラムを動かす環境です。Previewは、正式提供前の段階です。
| 項目 | 検証条件 |
|---|---|
| 配置先 | ap-northeast-1。CloudFrontはglobal |
| Web Functions | nodejs24.x、Node.js v24.21.0、arm64 |
| Event Functionsの比較用 | nodejs24.x、Node.js v24.21.0、arm64 |
| Event Functionsの最新Preview | nodejs26.x、Node.js v26.8.2、arm64 |
| SQSの受付Lambdaとworker | nodejs26.x(Preview)、arm64。Node.jsの実versionは未採取 |
| 実行環境 | Webは2GB。Eventは2,048MB、同時実行上限2 |
| Webの設定 | 環境数の上限2、環境内の同時処理数の上限1または8 |
| DB | Aurora PostgreSQL 17.5、Serverless v2、計算容量は0.5〜1 ACU。ACUは計算容量の単位 |
| 接続pool(接続を環境内で再利用する仕組み) | 環境ごとの最大接続数を1または4 |
| timeout | Webは6秒、Eventは10秒。CloudFrontの通常経路とHTTP APIの連携は8秒、短い経路は1秒 |
| 入口の受付上限 | Web endpointは毎秒100件。HTTP APIのstage(APIを公開する環境)は毎秒10件、瞬間的な受付上限も10件 |
| endpoint | WebはHomeRegion。1つのAWS Regionで実行する種類を選び、東京へ配置 |
Runtimeは、Web Functionsの対応一覧 と、Event Functionsの対応一覧 を分けて確認しました。2026年10月16日時点で、Node.js 26はPreviewです。APIの主な対照には、正式対応のNode.js 24を使います。SQSの受付Lambdaとworkerは、Preview runtimeでの検証です。

baseはWeb、api24とapi26は通常のLambdaです。下段のThrottlesは、同じ測定期間にLambdaが呼び出しを断った件数です。
endpointは、Web Functionsを呼ぶURLです。revisionは、コードと設定を固定した版です。DBの設定を比べる条件は、別のrevisionを別のendpointへ配置しました。
環境IDと、コードの版を示す値を応答とログへ入れました。ここでいう環境IDは、アプリ起動時に発行した値です。同じIDを返した呼び出しを、再利用された環境として数えます。設定した上限と、実際に使われた環境数は分けて数えます。
以下の実測画面は、2026年10月16日に測定したAWS応答の保存記録を、同日のCloudShellに表示したものです。件数は、同じ保存記録から数えています。画面のreqは、要求の記録番号です。
タイムアウトと注文の保存
重複対策なしの条件には、別の表unsafe_ordersを使いました。この表は行ごとのIDだけを主キーにし、注文IDには一意制約を付けません。同じ注文IDでも、INSERTのたびに別の行が増えます。
CloudFrontの待ち時間を1秒にし、DBへ保存する前か、保存した後に2.2秒待たせました。Web Functions側のtimeoutは6秒です。短い待ち時間の経路へ送り、その後、通常の経路から同じ注文を再送します。
接続が成功した後の測定では、最初のHTTP応答はすべて504でした。それでも、DBには注文が保存されました。再送を判断するときは、HTTP応答とDBの保存結果を分けて見ます。
| 条件 | 最初の応答 | 同じ注文を再送した後の保存件数 |
|---|---|---|
| 保存前に待機、重複対策なし | 504 | 2件 |
| 保存後に待機、重複対策なし | 504 | 2件 |
| 保存前に待機、注文IDを主キーにする | 504 | 1件 |
| 保存後に待機、注文IDを主キーにする | 504 | 1件 |
各条件を2回ずつ試し、再送はすべて200でした。クライアントのtimeoutを0.4秒にする対照も、保存前・保存後に分けて試しています。timeoutの後に2秒待ち、再送の前に主キーのある表から1件の保存を読み返しました。再送は両方200で、inserted=falseでした。insertedは、新しく登録したかを示します。最初の要求で保存され、再送では追加されなかったことを確認しました。
初期の2条件では、DB接続を待つ2.5秒の上限に達しました。再送も503となり、読み返した時点の保存件数は0件でした。原因は特定できていません。接続成功を確認した後、コードを変えずに上の全条件を測り直しています。

初期の接続失敗と再測定の保存記録です。firstは最初の応答、retryは再送の応答です。IDのbeforemsとaftermsは、保存前と保存後の待機を表します。ID末尾のtrueが重複対策なし、falseが主キーありです。DBは主キーあり、なしの順です。requestIdとdbRequestIdは、再送応答とDB読み返しを追う識別値です。retryNumberは、再送した要求の記録番号です。
DB側のSQLの実行期限も試しました。statement_timeoutを250msにし、INSERT前に2秒待つSQLを実行します。2回とも待機SQLが止まり、エラーコード57014となりました。アプリはROLLBACKを行い、HTTP 504を返しました。ROLLBACKは、DBの変更をまとめたtransactionを取り消す命令です。読み返した保存件数は0件でした。INSERT後の書き込みがROLLBACKで戻るかは、今回の測定には含めていません。
同じ注文の再送
重複対策には、DBの主キーとINSERTを使いました。先に件数を調べてから登録すると、その間に別のリクエストが入る可能性があります。重複を止める判断を、一つのINSERTへまとめます。
SQLの中心は次の部分です。
1
2
3
4
5
6
7
8
9
10
CREATE TABLE orders (
order_id text PRIMARY KEY,
revision text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
INSERT INTO orders (order_id, revision)
VALUES ($1, $2)
ON CONFLICT (order_id) DO NOTHING
RETURNING order_id;同じ注文IDを約0.1秒間隔で8件送り、応答待ちを重ねる条件も2回ずつ試しました。重複対策がない表には各8件、主キーのある表には各1件が保存されました。

約0.1秒間隔の送信、クライアントのtimeout、SQL取消しの保存記録です。DBは、重複対策あり、なしの順です。disconnect行のDBは、再送前の読み取りです。
8件を一斉に送る条件は未測定です。主キーとON CONFLICTによる競合の扱いは、PostgreSQLのINSERT仕様 でも確認しています。
これは、今回のDB登録を重複させない仕組みです。利用者ごとに注文IDを扱う場合や、同じIDで異なる内容が届く場合の判断は、実際の業務に合わせて加えます。
DBへの接続を抑える
環境内の同時処理数と、DB接続数は別に決めます。接続poolは、DBへの接続を環境内で再利用する仕組みです。環境が増えると、poolも増えます。
DB接続を0.8秒使う注文を、0.1秒以上の間隔で8件送りました。送信は毎秒10件以下、同時送信は最大8件です。環境数の上限は2に固定し、各条件を2回ずつ比べています。
| 条件 | 8件のHTTP結果。1回目/2回目 | 対象環境のDB接続数の観測最大 |
|---|---|---|
| Web:同時処理数1、pool1 | 200が2件、429が6件/同じ | 2 |
| Web:同時処理数8、pool1 | 200が6件、503が2件/200が7件、503が1件 | 2 |
| Web:同時処理数8、pool4 | 200が4件、429が4件/同じ | 4 |
| Web:同時処理数8、pool1、空きがなければ受付を断る | 200が2件、503が6件/同じ | 2 |
| HTTP API+Event:同時実行上限2、pool1 | 200が2件、503が6件/同じ | 2 |
429は、Web endpointのPlatform.EndpointMaxEnvThrottleでした。環境数の上限による拒否です。Eventの503はHTTP APIの応答で、同じ期間のLambda metricsにもThrottlesが記録されました。アプリの接続取得期限や受付拒否の503と分けます。
DB接続数は、接続の状態を調べるpg_stat_activityから取得しました。0.5秒の待機を挟み、取得時間も含む実際の間隔は約0.5〜0.8秒でした。応答の環境IDと照合し、対象の接続を数えています。

cap1は同時処理数1、baseは同8、pool4は接続poolの上限4です。guardTrueは空きがなければ受付を断り、guardFalseは接続取得期限まで待ちます。api24はHTTP API+Event24です。dbMaxは対象環境の接続数の観測最大、secは8件の全応答が返るまでの秒数、reqは最初の要求の記録番号です。画面の~0.5sは待機の設定値で、実間隔は約0.5〜0.8秒です。
pool1のbase endpointは、8件ともアプリへ届きました。うち1〜2件は、2.5秒の接続取得期限に達して503となりました。pool4のendpointは、2環境が2件ずつ受け付け、残り4件はendpointで429となりました。処理先と受け付けた件数が違うため、所要時間をpoolだけの効果に読み替えません。ここで確認したのは、対象のDB接続数の観測最大が2と4だったことです。
空きがなければ受付を断る条件では、約1.0〜1.1秒で全応答が返りました。拒否された要求は、呼び出し側で待機と再送を制御します。
環境数の設定を確かめる
環境数の上限を4にした条件は、2回とも8件すべて成功しました。実際には、2つの環境が4件ずつ処理しました。上限2の条件でも8件成功したため、成功数の差を上限変更の効果とは言えません。
上限を2へ戻した約1分半後に、base endpointから64件の注文を送りました。poolは各1です。DB接続を使う時間を0.8秒から0.4秒へ短くし、毎秒10件以下、同時に応答を待つ要求は最大8件としました。約13.5秒で64件すべてが成功しました。
復旧から約12分後、環境IDが入れ替わった状態で0.8秒の処理を再測定しました。1回目は8件とも新しい1環境へ届きました。2件が200となり、6件はアプリの接続取得期限で503となりました。2回目は2環境へ4件ずつ届き、8件すべて200でした。環境の暖まり具合はそろえていません。

測定順は、上限変更と復旧、64件送信、約12分後の再測定です。画面のsizing-restored2が再測定、sustained64が64件送信です。envsは200の応答の環境ID、secは全応答が返るまでの秒数です。
接続の予算は、環境数の上限とpoolから見積もります。運用時は、実際の環境数とDB接続数を追います。
キューへ受け渡す
すぐに登録結果を返す必要がなければ、受付と保存を分ける選択肢があります。HTTP APIから受付用Lambdaを呼び、SQSへ注文を送ります。SQSは処理待ちのメッセージを保存するサービスです。保存するworkerには、Event Functionsを使いました。
workerの同時実行上限は2、poolは環境ごとに1です。DB接続を0.8秒使う処理は、先ほどの同期処理と同じです。
8つの注文IDを送り、そのうち1つを意図的に再送しました。9件とも、受付を示す202が返りました。最初の応答は約0.78秒、その後は約0.10〜0.15秒です。
| 最後の受付からの待ち時間 | DBで読み返せた注文 |
|---|---|
| 約1秒 | 0件 |
| 約6秒 | 7つの注文ID、各1件 |
| 約66秒 | 8つの注文ID、各1件 |

待ち時間を1秒、5秒、60秒と追加し、最後の受付から約1秒、6秒、66秒の順で読み返しています。
8つの注文IDのうち、最初の1件だけworkerの初回を失敗させました。可視性タイムアウトは、受け取ったメッセージを他のworkerへ見せない時間です。今回は60秒にしたため、同じメッセージの再配送は約60秒後でした。この待ち時間があり、約6秒後は7件、約66秒後に8件となっています。同じmessage IDの2回目の配送で完了したことを、ログでも確認しました。意図的に2回送った注文ID queue-022107-1も、保存は1件でした。2通目の処理はinserted=falseでした。

CloudWatchから取得したログです。同じmessage IDで、queueRetryとattemptが2のqueueCompletedを確認しています。
202が示すのは受付です。受付後の状態確認、完了までの待ち時間、再試行と復旧の手順が増えます。SQSからの呼び出し では重複処理が起こり得るため、workerにも同じ注文を再登録しない設計が必要です。
I/O待ちを重ねる
Web Functionsの待ち時間の扱いを、DBを使わないタイマーで確かめました。200ms待つ非同期処理と、200msの間、同期的に計算し続ける処理を用意します。前者はI/O待ちを模したものです。I/O待ちは、DBや外部APIからの応答を待つ時間です。後者の計算中は、同じHTTPサーバーの別のリクエストが待たされます。待機と計算をそれぞれ200ms続け、要求の重なり方を比べます。
8件を同時に送り、条件ごとに2回試しました。
| 経路と設定 | I/O待ち | 同期計算 |
|---|---|---|
| Webへ直接。同時処理数1 | 各回2件成功、6件429 | 各回2件成功、6件429 |
| Webへ直接。同時処理数8 | 各回8件成功。全体0.304〜0.318秒 | 各回8件成功。全体0.896〜0.897秒 |
| HTTP API+Web。同時処理数8 | 各回4件成功、4件429 | 各回4件成功、4件429 |
| HTTP API+Event24。同時実行上限2 | 各回2件成功、6件503 | 各回2件成功、6件503 |
| HTTP API+Event26 Preview。同時実行上限2 | 各回2件成功、6件503 | 各回2件成功、6件503 |

cap1は同時処理数1、baseは同8の直接アクセスです。apiはHTTP API+Web、api24・api26はHTTP API+Eventです。ioはタイマー待ち、cpuは同期計算です。envsは200の応答の環境ID、secは8件の全応答が返るまでの秒数です。各条件を2回ずつ試しました。
直接アクセスのWebは、両方とも2環境で、各環境が4件ずつ処理しました。タイマー待ちは8件全体で約0.3秒、同期計算は約0.9秒です。同じ環境で待ち時間を重ねる場合と、同期計算で順に処理する場合の違いが出ました。
Event Functionsは、同時実行上限2により、同時に処理する環境は最大2つです。今回も2環境が各1件を処理しました。環境数の上限をどちらも2としたとき、Webの直接アクセスは8件、Eventは2件を受け付けました。速度に加え、受け付けた件数と拒否を合わせて見ます。
Web Functionsの同時処理数 は、AWSが使用状況に応じて変えます。設定値は、その上限です。直接アクセスのbaseは8件成功し、HTTP API経由の別endpointは4件でした。環境数と同時処理数の上限は同じです。差の原因は特定できていません。HTTPサーバーのI/O待ちを重ねたい場合に候補とし、実際の入口と依存先で負荷を確かめます。
HTTPの入口を決める
前の記事は「Lambda Web FunctionsとCloudFront・API Gatewayを連携してみる 」です。CloudFrontとHTTP APIの接続、cache、逐次応答を比べました。今回は、署名付きtokenのJWT、通常のLambda、pathの書き換えがない条件を加えています。
CloudFront、HTTP API、アプリの認証は、役割を分けました。利用者の認証には、検証用に発行した署名付きJWTを使っています。JWTは、発行元や利用者の情報を署名で確かめるtokenです。
アプリは署名、発行元、利用先、有効期限を確認します。利用者のJWTはX-App-Tokenへ入れました。HTTP APIの呼び出し元を確認するIAM署名が、Authorizationを使うためです。ここでは、検証用に発行したJWTの署名確認までを比べます。
OACは、CloudFrontから処理先へのアクセスを認証する設定です。
| 経路 | 呼び出し元から入口まで | 入口から処理先まで |
|---|---|---|
| CloudFront+Web | アプリがJWTを検証 | OACがIAM署名。対象distribution以外を明示的に拒否 |
| HTTP API+Web | routeでAWS_IAM。アプリもJWTを検証 | API Gatewayが専用tokenを上書きし、アプリが照合 |
| HTTP API+Event | routeでAWS_IAM。アプリもJWTを検証 | Lambda連携の呼び出し権限 |
CloudFrontからの経路では、LambdaがIAM認証を行います。同じaccountのIAM権限だけでも直接呼べるため、今回のpolicyでは対象のCloudFront以外をDenyで拒否しました。
HTTP API用のendpointはApplicationManagedです。Lambda自身は認証せず、アプリが共有の専用tokenを照合します。専用tokenが漏れると、正しい利用者JWTを持つ相手は直接呼べます。tokenの更新手順は未検証です。認証方式の仕様 に沿って、共有tokenの保管と更新は利用者が担います。
各経路で2人の正しいJWTは200、JWTなし・期限切れ・不正値は401でした。各条件を2回ずつ試しています。

1回目の認証結果を表示しています。cfはCloudFront、apiはHTTP API+Web、api24とapi26はHTTP API+Eventです。
CloudFront用endpointへ直接送る対照は、IAM署名の有無にかかわらず403でした。API Gateway用endpointへの専用tokenなしの直接アクセスも403です。呼び出し側が誤った専用tokenを付けても、API Gatewayが上書きした経路は200でした。利用者の認証と、処理先を呼べる相手の制限を、別に確かめています。

CloudFront用endpointへの直接アクセスは403でした。API Gatewayが専用tokenを上書きした要求は200です。
逐次応答の経路を選ぶ
公開データは同じURLへ8件送り、初回がMiss、残り7件がHitでした。後半4件は、前半で作られたcacheを再利用しています。個人別の応答はcacheを無効にし、private, no-storeを返しました。今回は、Event連携の逐次応答も比べます。
| 比べた条件 | 今回の結果 |
|---|---|
| CloudFront+Webで250ms間隔の3行を送信 | 2回とも約250ms間隔で到着 |
| HTTP API+Web/Event24/Event26で同じ3行を送信 | 各2回とも、3行をまとめて受信 |

kindがstreamの行は、arrivalMsに到着までのミリ秒を示します。kindがcacheの8行は、今回の公開データの記録です。
今回加えたEvent連携でも、受信側には3行がまとまって届きました。ここで使ったHTTP APIと、REST APIのresponse streaming は分けて判断します。
今回の逐次応答や公開データのcacheが要件なら、CloudFront+Webが候補になります。
日本語を含むURLの転送
前の記事では未確認だった、pathの書き換えを設定しない条件を加えました。入口によって結果が分かれています。同じ入力を送り、各条件を2回ずつ比べています。
1
/echo/%E6%97%A5%E6%9C%AC?q=%E6%97%A5%E6%9C%AC| 経路 | 結果 |
|---|---|
| CloudFront+Web | 200 |
| HTTP APIのHTTP_PROXY+Web | 400 |
| HTTP APIのLambda連携+Event24/26 | 200 |
HTTP_PROXYは、受け取ったHTTPリクエストを別のHTTPサーバーへ転送する連携です。今回はpathの書き換えがないIntegrationと、overwrite:pathを設定したIntegrationを別に作りました。
同じAPI、同じpath、同じ転送先で、書き換えなし、あり、なしへ戻す順に比べました。AWSから取得した実設定でも、指定の有無を確認しています。3段階とも、英数字のpathとqueryでは200でした。pathとqueryの両方に日本語を含む上のURLでは、400でした。

pathを書き換える設定の有無と、実際のHTTP結果を対応させています。
pathを書き換える設定の有無では、結果が変わりませんでした。今回の入力では、pathとqueryのどちらが400の原因かは分離できません。日本語を含むURLが必要なら、今回成功したCloudFront経由やEvent Functionsを候補に残します。採用前に、実際のURL形式で確かめます。
不良版から戻す
正常版goodと、不良版badを作りました。badは、注文IDが-badで終わるときだけ、保存後に500を返します。今回の更新前・段階配信・切り戻し後の注文は、すべて-badで終わるIDです。badへ振り分けられた注文は、必ず保存後に失敗する条件としました。不良版も、AWSが示す状態はActiveでした。
更新前に、判定基準を決めています。正常版で20件すべて成功することを確かめ、切り替え後の20件に1件でも失敗があれば戻します。戻した後は、正常版で20件連続成功することを確かめます。
| 段階 | 観測結果 |
|---|---|
| 正常版のみ | 20件すべて200 |
| 重み50:50へ変更した直後 | 注文はgoodが16件200、badが4件500 |
| 正常版100へ戻した後 | 20件連続でgoodの200 |
管理APIの更新完了と、実際の転送先は分けて見ます。重みを50:50にし、管理APIがSuccessfulを示した約3.5秒後に、healthの送信を始めました。状態確認用の8回は、すべてgoodでした。続く注文20件はgoodが16件、badが4件でした。配分の仕組みや、定常時の比率を測った結果ではありません。
切り替え時に処理中だったgoodの注文は、約2.5秒後に200を返しました。badが500を返した4件も、DBには保存されています。切り戻した後も、保存済みの注文はそのまま残りました。

20件の配信結果と、処理中の注文、版ごとのDB保存件数を表示しています。healthAfterShiftは、重み変更後、注文の前に送った8回の状態確認です。
戻した後、同じ4つの注文IDを再送しました。4件とも200となり、新規登録を示すinsertedはfalseでした。DBの保存は各1件のままです。

同じ4つの注文IDを再送し、insertedがfalse、保存件数が各1件であることを確認しています。
監視には、注文IDと版の識別値を残します。標準のWeb Functionsのmetrics にはrevisionの区別がないためです。HTTPの500、DBへの保存、戻した後の再送を、それぞれ追えるようにします。
料金の見積もり
Web Functionsは、request数、使ったCPU時間、環境が動いていた間のメモリを分けて見積もります。metricの仕様 では、CPU時間と稼働時間の単位はミリ秒、メモリはMegabytesです。CPUと稼働時間を1,000で割り、秒へ直しています。全環境の稼働時間は、環境ごとの秒数を足した値です。
CPU時間と稼働時間に値が記録されたのは、02:09〜02:30 UTCの22個の1分枠です。6つのendpointを含むWeb Function全体で、CPU時間は27.38 vCPU秒、全環境の稼働時間は7,618.609秒でした。観測した最大メモリは、AWSのmetric表記で190MBです。要求が0件だった1分間にも、CPU 131ms、メモリ最大159MBを記録した環境がありました。

02:09〜02:30 UTCの保存記録です。CPU時間と稼働時間は合計、メモリは最大値です。440件の内訳と、要求が0件だった1分間のCPU時間・メモリも表示しています。
東京のArm単価を使い、メモリが常に190MBだったと仮定すると、次の計算になります。request数の入力には、同じ取得時点の6つのendpointのExecutedRequestsを合計した440件を使っています。
| 項目 | 計算例 | 金額 |
|---|---|---|
| CPU | 27.38秒 × $0.0000322421 | 約$0.000883 |
| メモリ | 190 ÷ 1,024 GB × 7,618.609秒 × $0.0000042688 | 約$0.00603 |
| request | 440件 × $0.30 ÷ 100万件 | $0.000132 |
この記録範囲で、3項目の試算は約$0.00705です。メモリを一定と置き、1GBを1,024MBとして計算した例です。途中で取得したmetricsを使っています。単価は2026年10月16日に取得した東京Regionの料金カタログ で確認しました。
入口や依存先の料金も加えます。従量課金の最初の料金帯で計算する場合、次のような項目があります。表は、税、無料枠、割引を適用する前の単価です。
| 項目 | 単価を使う条件の例 |
|---|---|
| Event Functions | Armで$0.0000133334/GB秒と$0.20/100万呼び出し。今回の2GB設定では待ち時間も実行時間へ入る |
| HTTP API | 東京で最初の料金帯は$1.29/100万request |
| CloudFront | HTTPSは米国なら$1.00、日本なら$1.20/100万request。配信先の地域と転送量を確認 |
| Aurora Serverless v2 | 東京のPostgreSQLは$0.15/ACU時。0.5 ACUが1時間続けば$0.075。storageとI/Oは別 |
| VPC endpoint | 今回のSecrets Manager用は東京で$0.014/AZ時。2つのAZで1時間なら$0.028。処理データ量は別 |
| SQS | 東京の標準queueは最初の料金帯で$0.40/100万request。送信だけでなく受信・削除なども数える |
| CloudWatch Logs | 東京の標準logへの取り込みは$0.76/GB。保存と分析も加える |
今回は、配信拠点の範囲を絞るPriceClass_100 で試しました。対象は米国、カナダ、欧州、イスラエルです。最後の確認で返った拠点の識別値はSFO5-P1でした。CloudFrontの料金は、使われた配信拠点の地域に合わせて計算します。
専用tokenを保管するSecrets Managerや、コードを置くS3、データ転送も見積もりへ加えます。
AWSとアプリの分担
| 分担 | 今回の構成で扱うこと |
|---|---|
| AWSへ任せること | HTTPSのendpoint、実行環境の起動、負荷に応じた環境数と同時処理数の調整 |
| 利用者が守る条件 | HTTPサーバーを10秒以内に起動する。実行期限を守り、重要な状態はDBへ残し、要求ごとの状態を分ける |
| アプリ側に残る仕事 | 注文の重複対策、poolと環境数の上限、採用前のDB接続上限の確認、入口の認証、失敗を検知して戻す基準 |
| 保証されないこと | 設定した同時処理数まで常に使えること、同じ実行環境が続くこと。実際の応答と環境IDで確認する |
AWSが環境を増減しても、注文の正しさを保ち、DB接続数を調整する仕事はアプリ側に残ります。今回の429、接続取得期限の503、保存後の500は、それぞれ別の層で起きた結果です。再送、受付の制御、切り戻しを、原因のある層に合わせて設計します。
今回確認した範囲と、採用前に残る確認も分けます。
| 項目 | 今回の範囲と、残る確認 |
|---|---|
| 注文の重複対策 | DB登録まで。同一ID8件の一斉送信、外部決済、同じIDで内容が違う場合、INSERT後のROLLBACKは未検証 |
| DBと環境数 | 接続数とpool待ちを小規模な入力で確認。DB側の接続数上限(max_connections)、ACUの負荷、上限に近づく条件、接続確立と空き待ちの個別時間、最大処理件数、Eventの上限8での接続数は未測定 |
| 待ち時間の比較 | DBなしの200msタイマーと同期loop。入口やCPU配分が同じとは限らず、固定計算量や経路間の速度順位は比較対象外 |
| HTTPの入口 | 検証用JWTと短いstreamで確認。認証基盤、鍵の更新、長時間stream、大きな本文、日本語を含むURLの400の内部原因は未確認 |
| 配信拠点 | PriceClass_100の短い試験。拠点ごとの遅延と月間のcache効果は未測定 |
| 更新と料金 | Webの切り戻しを確認。Eventの更新、定常状態の50:50配信、実請求と月間予測は未検証 |
まとめ
どの構成でも、同じ注文を重複して保存しない仕組みを前提にします。そのうえで、今回の結果から選ぶ条件を整理します。
| 要件 | 候補 | 採用時に確かめること |
|---|---|---|
| Node.jsのHTTPサーバーを動かし、I/O待ちを同じ環境で重ねたい | Web Functions | 入口ごとの受付件数、実際の同時処理数、共有する接続pool、同期計算で他の要求を待たせる箇所 |
| DBの接続数に予算を設けたい | Webは環境数の上限×pool、Eventは同時実行上限×poolで見積もり、workerにも同じ考え方を使う | Webの観測最大は2・4接続、Eventは2接続。workerの接続数、DB側の上限と負荷は未測定。空き待ちか受付拒否かも決める |
| 今回のような逐次応答や公開データのcacheが必要 | CloudFront+Web | 利用者の認証、直接アクセスの拒否、cacheするデータ、配信拠点 |
| 今回のようにpathとqueryに日本語を含むURLを、HTTP APIから扱いたい | HTTP API+Event Functions | Honoのadapter、実際のURL、同時実行数と依存先が受けられる接続数 |
| 受付と完了を分け、混雑や一時失敗を後で処理したい | HTTP API+SQS+Event worker。今回はPreview runtimeで確認 | 重複対策、待ち時間、完了確認、採用するruntimeでの動作 |
| 不良版を段階配信し、正常版へ戻せるようにしたい | Web Functionsのrevisionと重み | 更新完了と転送先の差、DBに残る書き込み、版を識別するログ。Event側の切り替えは未測定 |
DBなしの200msタイマーでは、直接アクセス用のbase endpointが2環境で8件を処理しました。HTTP API経由の別endpointは、同じ環境数と同時処理数の上限で4件でした。差の原因は未確認です。入口ごとに受付件数を確かめ、Web Functionsの利点を判断します。
まず、受付時に保存完了まで返すか、後で処理できるかを決めます。次に、待ち時間を重ねる必要があるかを確かめ、HTTPの入口を選びます。最後に、必要なDB接続数と更新を戻す基準を確かめます。その結果に合う構成を、表の候補から選びます。
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article