![[AWS Lambda] Web Functions の課金は従来の Lambda とどれだけ違うのか、同じ待ち時間の負荷をかけて請求データで確認してみました](https://devio2024-media.developers.io/image/upload/f_auto,q_auto,w_3840/f_auto,q_auto/v1790870214/eyecatch/ylyxq1jyowp2zpiyvccj.png)
[AWS Lambda] Web Functions の課金は従来の Lambda とどれだけ違うのか、同じ待ち時間の負荷をかけて請求データで確認してみました
1 はじめに
製造ビジネステクノロジー部の平内(SIN)です。
2026 年 10 月に一般提供された AWS Lambda の Web Functions は、課金の考え方が従来の Lambda と大きく違います。従来は「実行時間 × 設定メモリ」でしたが、Web Functions は「使った CPU 時間」と「実行環境が存在する間の消費メモリ」を別々に数えます。料金ページにも LLM のストリーミング応答を例にした料金試算が載っていて、待ち時間が長く CPU をほとんど使わない処理に向いた課金に見えます。ただ、実際の請求で従来の Lambda とどれだけ違うのかは、ちょっと実感が湧いていませんでした。
Web Functions の課金に関しては、既に色々なブログで検証や試算が扱われています。
https://zenn.dev/aws_japan/articles/lambda-web-functions-vs-event-functions
https://qiita.com/asahide/items/5a7588552e5ffeef25b8
https://blog.serverworks.co.jp/lambda-web-functions-active-cpu-pricing
個人的には、以下のような切り口も気になってしまって、今回、作業してみました。
- 「消費メモリ」は、どう数えられているのか
- 同時にたくさん来るとき、本当に安くなるのか。一度にドッと来るバーストでも同じか
- リクエストがまばらなとき、どこから従来の Lambda の方が安くなるのか
同じアプリを Web Functions と従来の Lambda(512 MB と 2048 MB)に載せ、同じ待ち時間の負荷をかけて、CloudWatch のメトリクスと CUR の請求データで確かめてみました。
先に結論を述べると、次のとおりです。
- メモリは「実行環境ごとの生涯ピーク × 存在時間」で課金されていました。一度 1 GB を掴むと、手放した後も環境が消えるまで 1 GB で課金されます
- 持続的に同時に来る負荷では、Web Functions は従来の 512 MB の約 1/25 でした。ただし、300 件が一度に来る単発のバーストでは、逆に 512 MB の約 6 倍でした
- 1 件ずつの直列でも約 1/3.4 ですが、2 分に 1 件の散発では 512 MB の約 2.65 倍でした。損益分岐は「1 分に 1 件」ぐらいでした
なお、本稿はあくまで特定環境(東京リージョン、Arm、Node.js の Hono アプリ)での一例として捉えてください。単価は 2026 年 11 月 8 日に確認したものです。
2 課金モデル
公式ドキュメントに書かれている内容を整理してみます。
(1) 課金の単位
| 従来の Lambda(Event Functions) | Web Functions | |
|---|---|---|
| 課金の対象 | リクエスト数 + 実行時間 × 設定メモリ(GB-秒) | リクエスト数 + CPU 時間(vCPU-秒) + 実行環境が存在する間の消費メモリ(GB-秒) + データ転送 |
| CPU | 設定メモリに比例して割り当て(1,769 MB で 1 vCPU 相当) | アプリとランタイムが実際に使った CPU 時間。1 ms 単位 |
| メモリ | 設定したメモリ量 | 実行環境が消費したメモリ量。リクエストの間のアイドル時間も含む |
https://aws.amazon.com/lambda/pricing/
https://docs.aws.amazon.com/lambda/latest/dg/web-functions.html
ポイントは、Web Functions のメモリが設定値ではなく消費量で課金される点です。料金ページには次のように書かれています。
Each execution environment is billed for the memory it consumes, for as long as it runs, including time between requests.
ただし、「消費したメモリ量」をどう測るのか(ピークなのか、一定間隔のサンプルなのか)は、見つけられませんでした。
(2) 実行環境
| 項目 | 値 |
|---|---|
| vCPU / メモリ | 2 vCPU / 2 GB(変更不可) |
| 1 環境の同時リクエスト数の上限(maxConcurrencyPerEnvironment) | 既定 64、範囲 1〜128 |
| 実際の同時リクエスト数 | Lambda がリソースの使用状況から動的に決める(上限は超えない) |
| 環境の増減 | 需要に先回りして予備の環境(headroom)を立てる。トラフィックが無ければゼロまで減らす |
https://docs.aws.amazon.com/lambda/latest/dg/web-functions-scaling.html
https://docs.aws.amazon.com/lambda/latest/dg/web-functions-env-lifecycle.html
アイドルになった環境が何分後に削除されるかは分かりませんでした。ライフサイクルのページには、環境が特定の時間、存続することを前提にしないように、となっていました。
(3) メトリクス
| メトリクス | 単位 | 定義 |
|---|---|---|
| EnvironmentActiveTime | ミリ秒 | 実行環境がアクティブだった時間。初期化を含む |
| EnvironmentCPUTime | ミリ秒 | 実行環境が消費した vCPU 時間。初期化を含む |
| EnvironmentMaxMemoryUsage | MB | 実行環境がその生涯でこれまでに使ったメモリのピーク |
https://docs.aws.amazon.com/lambda/latest/dg/web-functions-monitoring-metrics.html
(4) 東京の単価
AWS Price List API の東京リージョン(ap-northeast-1)の値です(2026 年 11 月 8 日に確認)。
| 項目 | Web Functions(東京、Arm) | 従来 Lambda(東京、Arm) |
|---|---|---|
| リクエスト | $0.30 / 100 万 | $0.20 / 100 万 |
| CPU | $0.0000322421 / vCPU-秒 | (メモリに含まれる) |
| メモリ | $0.0000042688 / GB-秒(消費量) | $0.0000133334 / GB-秒(設定値) |
https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AWSLambda/current/ap-northeast-1/index.json
GB-秒あたりの単価は、Web Functions が従来の約 1/3.1 です。本稿の金額は、すべてこの単価から計算した値です。
3 設計と構築
(1) アプリ
待ち時間の長い処理の代表例は LLM の応答待ちですが、応答時間がばらつき、レート制限も混ざるため、今回は Bedrock を使いませんでした。Lambda 側の課金の差を切り分けにくいからです。
代わりに、GET /wait?ms=N で N ミリ秒だけ待って返す擬似 LLM を用意しました。待ち時間を揃えれば、両者の差は課金モデルの差だけになります。加えて、GET /wait?ms=N&mb=M で、待っている間だけ M MB の Buffer を保持できるようにしています。
Github app/src/index.ts
// 要点抜粋
app.get('/wait', async (c) => {
const ms = Number(c.req.query('ms') ?? 0)
const mb = Number(c.req.query('mb') ?? 0)
const held = mb > 0 ? Buffer.alloc(mb * 1024 * 1024, 1) : null // 1 で埋めて物理メモリに乗せる
await new Promise((r) => setTimeout(r, ms))
return c.json({ ms, mb, env: ENV_ID, heldMb: held ? held.length / 1024 / 1024 : 0 })
})
(2) 構成

同じ Hono アプリを 3 つの Lambda に載せ、CDK(L1 コンストラクトの CfnWebFunction など)で作りました。
Github cdk/lib/stack.ts
| 種類 | 入口 | メモリ | |
|---|---|---|---|
| A-512 | 従来の Lambda + Lambda Web Adapter | Function URL | 512 MB |
| A-2048 | 従来の Lambda + Lambda Web Adapter | Function URL | 2048 MB |
| B | Web Functions | Endpoint(認証なし) | 2 GB 固定(課金は消費量) |
従来の Lambda はハンドラー関数を呼び出す仕組みなので、HTTP サーバーとして書いたアプリはそのままでは動きません。そこで従来側には Lambda Web Adapter(LWA)のレイヤーを付け、Web Functions と同じ index.js をそのまま動かしています。アプリのコードを揃えて、課金の違いだけを比べるためです。
(3) 負荷パターン
負荷は手元の Mac から Node.js のスクリプトでかけ、3 つに同時に同じパターンを流しました。応答に実行環境の識別子を含めて、どの環境で処理されたかを数えています。
| パターン | 内容 | 確かめたいこと |
|---|---|---|
| 同時 10 | 10 件同時 × 25 回(待ち 1 / 5 / 20 秒) | 持続的に同時に来る負荷 |
| 同時 64 | 64 件同時 × 10 回(待ち 5 秒) | 同上。既定の上限 64 |
| バースト | 300 件同時(待ち 3 秒)を 1 回、または 3 分おきに 5 回 | 一度にドッと来る負荷 |
| 直列 | 1 件ずつ 60 回(待ち 5 秒) | 分け合えない負荷 |
| 散発 | 2 分おきに 1 件 × 15 回(待ち 5 秒) | まばらな負荷 |
| メモリ保持 | 1 件ずつ 10 回(待ち 5 秒 + 1,000 MB を保持) | メモリの数え方 |
パターンの間は 10〜15 分空け、Web Functions の実行環境がゼロに戻ってから次を始めました。バーストは関数を作った直後に流しました。作った直後は 1 環境に入る件数が少なく環境が多く立つため、Web Functions の maxEnvironments(環境数の上限)を、バーストのときだけ 4 から 150 に上げています。
Github scripts/load.mjs
(4) バージョン
| 項目 | バージョン |
|---|---|
| hono / @hono/node-server | 4.13.13 / 2.1.5 |
| aws-cdk-lib / aws-cdk | 2.273.0 / 2.1145.0 |
| Lambda Web Adapter | LambdaAdapterLayerArm64:30(1.1.0) |
| Node.js ランタイム | nodejs24.x(両方、Arm64) |
| 手元の Node.js / pnpm | 22.14.0 / 10.24.0 |
| リージョン | ap-northeast-1 |
4 メモリの数え方
Web Functions の金額は、負荷パターンごとに CloudWatch のメトリクスから計算し、従来の Lambda と比べています。請求データは 1 日分がまとめて出るだけで、パターンごとには分かれないためです。そこでまず、その計算に使う「消費メモリ」の数え方を確かめてみました。
(1) メモリ保持
1,000 MB の Buffer を 5 秒ずつ 10 回(合計 53 秒)だけ掴んで手放すパターンです。.local ロググループの invokeSummary を 1 分ごとに追うと、次のようになりました。
14:01 requests=10 maxMemoryUsageMb=1156 # 保持中
14:02 requests=0 maxMemoryUsageMb=1156 # 手放した後も 1156 のまま
14:06 invokeReport totalDurationMs=339800 maxMemoryUsageMb=1156
Buffer を手放した後も、環境が消えるまで 1156 MB のままです。この値がそのまま課金に使われるなら、53 秒だけ 1 GB を使った環境は、残りの 287 秒も 1 GB で課金されます。その場合は $0.001706 になり、従来の 2048 MB($0.00137)の 1.25 倍です。
CloudWatch の EnvironmentMaxMemoryUsage(5 分ごとの最大、時刻は UTC)でも、14:00 に 1,156 MB へ上がった後、環境が消えるまで下がっていません。

(2) CUR
実際の請求は、CUR(Cost and Usage Report)で確認しました。CUR には関数名が入るので、関数ごとの使用量が分かります。
メモリ保持を含む計測分について、2 通りの数え方と請求量を比べた結果です。
| 数え方 | GB-秒 |
|---|---|
| 環境ごとのピーク × 存在時間 | 1,004 |
| 毎分の実使用量 | 約 750 |
| CUR の請求量 | 1,001 |
請求量は、ピークで数えた値と一致しました。メモリは「環境ごとのピーク × 存在時間」で課金されていると判断し、以降の金額もこの式で計算しています。CPU 時間とリクエスト数も、CloudWatch の値とそのまま一致しました。
5 同時に来る負荷
次に、同時にたくさん来るとき、本当に安くなるのかを見てみました。
| パターン | Web の環境数 | Web Functions | 従来 512 MB | Web / 512 |
|---|---|---|---|---|
| 同時 10 × 25 回 | 1 | $0.00044 | $0.0107 | 0.04 |
| 同時 64 × 10 回 | 2 | $0.00081 | $0.0215 | 0.04 |
| バースト 300 件 × 1 回 | 150 | $0.0369 | $0.0063 | 5.9 |
| バースト 300 件 × 3 分おき 5 回 | 150 → 37 | $0.0581 | $0.0315 | 1.8 |
同時 10 と同時 64 は、Web Functions の環境が 1〜2 つで済み、従来 512 MB の約 1/25 でした。従来の Lambda は 1 リクエストに 1 環境なので、同時 10 件なら 10 環境分の料金がかかります。
同時 10 と同時 64 を流したときの、Web Functions の環境数です(5 分ごとの最大、時刻は UTC)。

ただ、300 件が一度に来るバーストでは、逆に約 6 倍かかりました。1 環境に 2 件しか入らずに 150 環境が立ち、それぞれが約 6 分残ってメモリ代がかかったためです。
バーストのときの、Web Functions の環境数と従来 512 MB の同時実行数です(1 分ごとの最大、時刻は UTC)。

1 回目のバーストの後は、リクエストが来ていなくても、約 6 分間アクティブ時間が積み上がっています。

3 分おきに繰り返すと、環境が残っている間に次が来るので、1 環境あたりの件数が 2 から 9 まで増え、約 1.8 倍まで下がりました。

Web Functions が安くなるのは、少ない環境にリクエストが繰り返し来るときでした。
6 まばらな負荷
最後に、リクエストがまばらなとき、どこから従来の Lambda の方が安くなるのかを見てみました。
| パターン | 件数 | Web Functions | 従来 512 MB | 従来 2048 MB | Web / 512 |
|---|---|---|---|---|---|
| 直列 1 件ずつ 60 回 | 60 | $0.000595 | $0.00202 | $0.00805 | 0.29 |
| 散発 2 分おき × 15 回 | 15 | $0.001334 | $0.000504 | $0.00201 | 2.65 |
直列では、環境は 1 つで、消費メモリは 160 MB でした。512 MB を 5 秒ずつ占有する従来より安く、約 1/3.4 です。
散発では逆転しました。2 分おきでは環境が消えないので、30 分間ずっと存在し続け、その間のメモリが課金されます。
散発の時間帯の、Web Functions の環境数です(5 分ごとの最大、時刻は UTC)。14:15 から 14:45 まで、環境が 1 つのまま存在し続けています。

154 MB の環境 1 つの存在コストは約 $0.0000385/分です。512 MB で 5 秒のリクエスト 1 件は $0.0000335 なので、「1 分に 1 件」あたりが損益分岐になります。
最後のリクエストから環境が消えるまでは、4 分 40 秒〜約 6 分でした。shuntaka さんの記事でも、377 環境のうち約 84% が最後のリクエストから 5〜7 分で終了したと報告されています。
7 選び方
今回の結果から、待ち時間が長く CPU をほとんど使わない処理での判断の目安を表にします。
| 到着のしかた | 安いほう | 理由 |
|---|---|---|
| 同時に複数件が、途切れずに来る | Web Functions | 少ない環境にまとまり、リクエスト数に比例しない |
| 1 件ずつだが途切れない(1 分に 1 件以上) | Web Functions | 消費メモリ 160 MB の環境は、512 MB を占有する従来より安い |
| 一度にドッと来て、しばらく来ない | 従来の Lambda | 環境が一気に増え、それぞれが消えるまでメモリ代がかかる |
| 1 分に 1 件未満の散発 | 従来の Lambda | 環境が消えるまでの約 5 分のメモリ代が効く |
| 短時間だけ大きなメモリを使う | 従来の Lambda | ピークのまま、環境が消えるまで課金される |
8 最後に
実務で意識した方が良さそうだと感じた点は以下です。
- 移行前に、今の Lambda の Invocations と ConcurrentExecutions を 1 分単位で見ておくと判断しやすいと思います。リクエストが途切れずに重なっているなら Web Functions、まばらだったり山が鋭かったりするなら従来の方が向いていそうです
- Web Functions の費用は、CloudWatch の EnvironmentMaxMemoryUsage × EnvironmentActiveTime と EnvironmentCPUTime で、請求を待たずに見当が付けられます
- アプリの消費メモリと、一時的なメモリスパイクがそのまま費用に効きます。大きなメモリを短時間だけ使う処理は、別の関数に分けるか、従来の Lambda に残すのが良さそうです
Web Functions の課金は「環境が生きている時間」に対する考え方が従来と違うので、アクセスパターンを見て選ぶ必要があると感じました。この記事の数字が、その判断のたたき台になれば嬉しいです。
この記事で使用したコードは、以下に置きました。
9 参考リンク
- AWS Lambda Pricing
- Lambda Web Functions(開発者ガイド)
- Web Functions のメトリクス
- Scaling behavior for Lambda Web Functions
- Execution environment lifecycle
- AWS Price List API(AWSLambda、ap-northeast-1)
- AWS Lambda Web Adapter
- Lambda Web Functions と従来の Lambda の実行環境と課金の違いを実測から確かめてみた(Zenn)
- Lambda Web Functions にアプリを載せ替えて料金と速さを比べてみた(Qiita)
- AWS Lambda Web Functions で LLM の待ち時間は課金されない? アクティブ CPU 課金で得する処理・損する処理(サーバーワークスエンジニアブログ)
- 個人ブログを Lambda Web Functions + CloudFront に移行して、実際の料金を確認してみた











