AWS Builder Center

Lambda Web FunctionsでHTTP serverを動かしてみる

東京regionでLambda Web Functionsを検証しました。同じ環境での並行処理、HTTP streaming、429とtimeoutを、実測とログから追います。

Series: Try Lambda Web Functions (4 articles)

  1. 1
    Lambda Web FunctionsでHTTP serverを動かしてみる This article
Senior Evangelist

HTTP serverを動かしてみる

Lambda Web Functionsでは、同じHTTP serverで複数のrequestを処理できました。今回の検証では、500msの非同期待ちは同じ環境で2件重なりました。一方、同期CPU処理は同じ環境で順番に進みました。
環境の起動や台数の調整をAWSへ任せ、HTTP serverを動かしたい場面が対象です。Web Functionsでは、HTTPS終端と実行環境の管理をLambdaが担います。同じprocessのrequestをどう分けるかは、アプリ側の設計に残ります。東京regionで、非同期待ち、streaming、失敗時の扱いを確かめました。
 2026年10月12日の発表 で、従来のLambda関数にはLambda Event Functionsという名前が付きました。既存関数のコード変更やredeployは不要です。Web Functionsは、HTTPの待ち受けを行う別の実行モデルです。

検証時の構成

同じZIPから2つのrevisionを作りました。revisionは、コードと設定を固定したversionです。変えたのは、1環境あたりのrequest数の上限です。1と8を、それぞれ別のendpointへ割り当てました。

東京regionの2つのIAM認証endpointとrevision、S3のコード、CloudWatch Logsの流れ

検証時の構成です。青はHTTPの往復、紫はログ、破線はS3からのコードの読み込みを示します。
項目
条件
region
ap-northeast-1
runtime
nodejs24.x、実際のNode.jsはv24.21.0
architecture
Arm64
endpoint
HomeRegion、IamAuth
maxConcurrencyPerEnvironment
1 / 8
maxEnvironments
各endpointで2
rateLimit
各endpointで100 RPS
timeoutSeconds
両revisionとも3秒
Web Functionsの 対応runtime は、今回の確認時点では正式対応のNode.js 24でした。実行環境は、serverのprocessが動く単位です。maxEnvironmentsの下限は2です。1環境へ固定する実験にはせず、同じprocessの処理を追いました。環境IDはserver起動時に生成したUUIDです。Lambdaが付けるrequest IDと合わせて、ログと応答を照合しました。
resourceはCDKで作成しました。コード用S3 bucketはversioningを有効にし、同じobject versionを両revisionへ指定しました。呼び出しにはSigV4、AWSの署名方式を使いました。 IAM認証の要求 に合わせ、service名をlambdaとし、payload hashも付けています。

HTTPの待ち受け

Lambda用handlerへHTTP eventを変換するadapterは使いませんでした。Node.js標準のnode:httpでserverを起動しています。起動部分は次のコードです。
JavaScript
const address = process.env.AWS_LAMBDA_HTTP_ENDPOINT ?? "127.0.0.1:3000";
const separator = address.lastIndexOf(":");
const host = address.slice(0, separator).replace(/^\[|\]$/g, "");
const port = Number(address.slice(separator + 1));
server.listen(port, host);
serverには、500msの待ち、100msのCPU処理、250ms間隔のstreamingを選ぶrouteを用意しました。署名したrequestのpathとqueryは次の形です。
text
GET /work?kind=wait&ms=500&trace=wait_sample
GET /work?kind=cpu&ms=100&trace=cpu_sample
GET /stream?mode=stream&ms=250&count=4&trace=stream_sample
GET /stream?mode=buffered&ms=250&count=4&trace=buffered_sample
AWS_LAMBDA_HTTP_ENDPOINTは、Lambdaが指定する待ち受け先です。Web Functionsでは、そのhostとportへbindします。外側のHTTPSをLambdaが終端し、serverへHTTP requestを渡します。
GETではqueryのsample=helloを読み取れました。POSTのbodyには、送ったJSON文字列が残りました。不正な待ち時間を渡すと、アプリの入力検査がHTTP 400を返しました。HTTPのmethodやbodyを、通常のrequest objectから読む形です。
 revisionとendpointの仕様 では、Activeの状態だけでserverの起動は確認できません。配置後に、実際のHTTP要求とログで動作を確認しました。

同じ環境の並行処理

非同期待ちでは、上限8のほうが上限1より多くのrequestを処理できました。healthで動作を確認し、上限8では2・4・8件の待ち処理でwarm-upしました。その後、8件を並行に送り、各条件を2回試した結果です。
処理
1環境の設定上限
送信
HTTP 200
HTTP 429
同じ環境で観測した最大の重なり
非同期待ち500ms
1
16
4
12
1
非同期待ち500ms
8
16
8
8
2
同期CPU処理100ms
8
16
8
8
1
待ちは、外部DBへ接続せず、Promiseのtimerで作りました。CPU処理は、main threadを100ms占有するloopです。速さの優劣を比べる入力ではなく、同じprocessで処理が重なる条件を分けています。
JavaScript
// 非同期待ち
await delay(ms, undefined, { signal: controller.signal });

// main threadを占有するCPU処理
const deadline = performance.now() + ms;
while (performance.now() < deadline) {
// 指定した時間だけevent loopを塞ぐ
}

wait1・wait8・cpuの処理完了数と、同じ環境で重なったrequest数を比較したCloudWatchログ

processedはserver側で処理を終えた件数、maxActiveは同じprocessで観測した最大の重なりです。testは処理条件、environmentsは起動時UUIDで区別したprocess数です。拒否されたrequestはserverへ届かず、この集計には入りません。HTTP 429の件数はclient側の応答から数えました。
上限8は、常に8件を同時処理する設定ではありません。 scalingの仕様 では、Lambdaがresource使用量に応じて環境内の並行数を調整します。今回の2件を、その動的な上限の値とは確認できていません。429のerror headerは、すべてPlatform.EndpointMaxEnvThrottleでした。環境数を2に絞った条件での結果です。
CPU処理では、同じ環境の2つのcallbackが順番に始まりました。clientの成功応答は、各環境の1件目が約173〜177ms、2件目が約269〜277msでした。Node.jsのevent loop、処理を進める仕組みを同期処理が塞ぐと、後続のrequestも待ちます。worker threadsなどへCPU処理を分ける案は、今回の実測範囲には含めていません。

HTTP streaming

serverが生成したJSONを順に返すと、最初の1行は約0.33秒で届きました。4行を保持してから返すbuffered応答では、約1.08秒後にまとめて届きました。
250msごとにJSONを1行作り、4行返しています。ここでは1行を1chunkとして記録しました。clientはTLS接続を始める直前から、各行を読み終えるまでを測っています。
mode
試行
chunk 1
chunk 2
chunk 3
chunk 4
stream
1
328.7ms
579.0ms
829.7ms
1080.7ms
stream
2
326.4ms
576.6ms
827.7ms
1078.5ms
buffered
1
1080.2ms
1080.2ms
1080.2ms
1080.3ms
buffered
2
1088.0ms
1088.1ms
1088.1ms
1088.1ms
streamではresponse.writeを各回に呼びます。bufferedでは配列に保持し、最後にresponse.endへ渡しました。実測コードの処理部分です。
JavaScript
const lines = [];
response.writeHead(200, { "content-type": "application/x-ndjson" });
for (let index = 1; index <= count; index++) {
await delay(intervalMs, undefined, { signal: controller.signal });
const line = `${JSON.stringify({ ...details(), index })}\n`;
if (mode === "stream") response.write(line);
else lines.push(line);
}
response.end(mode === "buffered" ? lines.join("") : undefined);

JSONを250msごとに生成し、streamで都度書き込み、bufferedで保持したCloudWatchログ

これはserver側のログです。written=1が各chunkを書き込んだ行です。written=0は最後まで保持した行です。request IDをclientの応答と照合しました。画像のelapsedMsはserver内の経過時間で、上の表はclientの受信時間です。
生成に約1秒かかる処理でも、途中の結果を先に渡せました。実際のAI推論やDB接続は試していません。先にJSONを届ける経路を、標準HTTPの処理で確かめた結果です。

失敗とtimeout

HTTP 500を返すrouteへ、同じtraceを付けて2回送りました。両方とも500でした。request IDは別々になり、serverのログにも2回の実行が残りました。その後のhealth要求は200でした。これを2組試しています。

同じtraceの2回のHTTP 500と、その後のHTTP 200を示すCloudWatchログ

ordinalは、各processが受けたrequestの通し番号です。今回の2組では、再送は別のprocessへ届きました。
clientに自動retryは入れていません。ここで行ったのは、明示した2回の送信です。再送を設計するときは、業務処理の重複を防ぐIDと、その処理の完了条件をアプリ側で持ちます。
次に、5秒待つ要求を3秒のtimeoutへ送ると、2回ともHTTP 504になりました。error headerはRuntime.RequestTimeoutでした。clientの全体時間は3075.4msと3082.8msです。その後のhealth要求はいずれも200でした。

3秒付近でのrequest切断と、後続health要求のHTTP 200を示すCloudWatchログ

serverでは接続のcloseを監視し、AbortControllerで待っていたtimerを中断しました。今回の副作用はtimerだけです。timeoutになった業務処理をどう確定し、外部への書き込みをどう扱うかは、別に設計する必要があります。

まとめ

非同期の待ちが多いNode.jsのHTTP serverでは、同じ環境でrequestを重ねて処理できました。streamingも、標準のresponse.writeで途中のJSONを届けられました。
その分、requestごとの状態を分け、同期CPU処理の占有を抑える設計が要ります。設定した上限と実際の重なり、429、timeoutを一緒に見て、依存先へ通す量を決めます。
 課金の軸 はrequest、active CPU、環境が存在する間のmemoryなどです。今回の測定は処理と応答の挙動で、請求額や費用削減率は測っていません。
公式の 用途の分け方 では、HTTPの処理にWeb Functions、queue messageやfile uploadの処理にEvent Functionsを案内しています。今回の実測は、HTTPを入口にした条件に限ります。

Series: Try Lambda Web Functions (4 articles)

  1. 1
    Lambda Web FunctionsでHTTP serverを動かしてみる This article
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article