AWS Builder Center

Serverless DeepDive #04:LambdaとFargateを同じjobで比較してみる

#03の商品登録jobを、Lambda、Fargateの常駐worker、1job1taskで動かしました。処理開始までの時間、処理中にtaskを止めたときのjobの状態、待機中の課金時間を実測し、jobを動かす実行基盤を選ぶ条件を整理します。

Series: Serverless DeepDive (13 articles)

  1. …
  2. 5
    Serverless DeepDive #04:LambdaとFargateを同じjobで比較してみる This article
Senior Evangelist
#03 では、完了を待たずに受付を返してよいjobを考えました。今回は、そのjobをどこで動かすかを考えます。
候補は、Lambdaの関数と、Amazon ECS on AWS Fargateです。Fargateは、動かし続けるworkerと、jobごとに起動するtask(1job1task)の2通りを試しました。#00 では、常駐するprocessや、複数の処理にまたがる接続が要件ならFargateを考える、と書きました。その境目を、同じjobで確かめます。
Fargateでも、containerを動かすサーバーの管理はAWSに任せられます。ただし、taskをいつ起動して止めるか、jobをどう受け渡して再試行するかは、利用者が決めます。Lambdaでは、ここまでAWSが行います。
jobを1件ずつ続けて送ったときは、処理開始の速さにほぼ差がありませんでした。差が出たのは、処理中に止めたときのjobの扱いと、jobがない時間の課金です。料金表からの推計では、2.5秒のjobなら、1時間に約680件(public IPv4込みで約950件)までLambdaのほうが安くなります。

検証構成

jobの中身は#03と同じです。数量を検査し、指定した時間だけ待ち、S3へ状態と結果を書きます。jobのコード(job.cjs)は1つで、LambdaのcodeもFargateのimageも、CDKが同じdirectoryから作りました。
jobの届け方は3通りです。
  • Lambda: PCから非同期Invoke(Event)で呼びます。
  • 常駐worker: PCからSQSへ送ります。RunTaskで起動しておいたFargateのworkerが、long polling(今回は5秒待ち)で受け取ります。ECS Serviceは使っていません。
  • 1job1task: PCからRunTaskでtaskを起動し、環境変数でjobを渡します。taskは1件処理して終わります。
条件設定
Regionap-northeast-1(Tokyo)
Lambdanodejs26.x(public Preview)、512 MB、arm64、timeout 30秒、非同期の再試行0回
FargateARM64、0.25 vCPU、512 MiB、stopTimeout 20秒、public subnet(NATなし、public IPあり)、image約145 MB(圧縮)
SQSStandard queue、可視性timeout 60秒
通常のjobquantity 2、workMs 2500(約2.5秒)
状態の確認PCからS3を0.25秒間隔で読む
stopTimeoutは、taskを止めるときにSIGTERMを送ってから、強制終了のSIGKILLまで待つ時間です。可視性timeoutは、受け取られたmessageを、他の受信者から隠しておく時間です。
Node.js 26は、検証時点でLambdaの最新のNode.js runtimeで、runtime一覧 ではpublic Previewです。SLAとTechnical Supportの対象外なので、本番では正式提供のruntimeで確かめ直す必要があります。
測定は2026-10-09に行いました。停止したECSのtaskはDescribeTasks で参照できる期間が限られ、撮影の前に消えていました。そのため図4と図5は、翌日に同じ手順を撮影用に1回ずつ実行した画面です。本文の数値は、2026-10-09の測定の値です。
PCから同じjobをLambdaの非同期Invoke、SQS経由の常駐worker、RunTaskの1job1taskへ送り、3つともS3へjob状態を保存する構成。ECSのStopTaskで常駐wo
図1:検証した構成です。jobのコードは共通で、jobの届け方と、taskとjobの止め方を変えました。
AWS CloudShellでLambdaを呼び、platform lambdaのNode.js v26.8.2とSDK 3.1105.0、S3に残ったFargateのtaskの記録からNode.js
図2:撮影時にLambdaを1回呼んだ結果と、2026-10-09にFargateのtaskが書いた記録です。実行時のNode.jsは、Lambdaがv26.8.2、Fargateがv26.10.0でした(minor versionが違います)。stは、S3の記録をjqで抜き出す撮影用の関数です。

同じjobを18回ずつ処理する

通常のjobを、Lambdaと常駐workerへ18回ずつ送りました。前のjobの完了を確かめてから次を送る、1件ずつ続けて届く条件です。workerはいつも空いていて、jobが重なる場合は測っていません。
経路処理中を確認するまで完了を確認するまで
Lambda(Event)中央値0.439秒(0.391〜0.715秒)中央値2.902秒
常駐worker(SQS)中央値0.374秒(0.357〜0.465秒)中央値2.841秒
時間は、PCで送信を始めてから、S3でその状態を読むまでです。差は中央値で約0.07秒で、確認の間隔の0.25秒より小さい値でした。1件ずつ続けて届く間は、処理開始の速さで選ぶ理由はありません。
新しい実行環境で始まると、Lambdaには初期化が加わります。比較の約11分後に送ったjobは、新しい実行環境で始まりました。初期化(Init Duration)に887.50 msかかり、処理中の確認まで1.691秒でした。常駐workerは、約6分空けた後も0.471秒でした。どちらも1回の観測です。
jobをまたいでmemory上の値を保つ点は、両方とも同じでした(図3)。違うのは、保つ期間を誰が決めるかです。workerのprocessは、taskを止めるまで動き続けます。Lambdaの実行環境は、呼ばれ続けていても、数時間ごとにAWSが終了します(実行環境のlifecycle )。
S3に残ったjobの記録を4件表示した画面。l-g1-1とl-g3-6はlambdaの実行環境d23f5f08で件数2と19、f-g1-1とf-g3-6はfargateのprocess 54e7665
図3:比較の最初と最後のjobの記録です。Lambdaは18件とも同じ実行環境(d23f5f08)、workerも同じprocess(54e76659)で、件数を数え続けています。Lambdaの件数が2から始まるのは、比較の前にversionを確かめた呼び出しが1件あるためです。

1job1taskで起動してみる

jobごとにtaskを起動する方法を、6回試しました。RunTaskから処理中を確認するまで、中央値で約23秒かかりました。
区間中央値範囲
RunTaskから処理中を確認するまで(PC)22.98秒20.69〜28.76秒
taskの作成からimageの取得開始まで(ECS)13.29秒11.48〜15.67秒
imageの取得(ECS)5.88秒5.67〜11.02秒
taskの作成からcontainerの開始まで(ECS)19.99秒17.85〜25.91秒
2.5秒のjobに、約20秒の起動が加わります。imageの取得は約6秒で、取得を始めるまでの時間のほうが長くかかりました。
1件ごとに数十秒待てる長いjobなら、候補になります。Lambdaの1回の実行は最大15分 です。Decision Guide によると、Fargateのtaskには実行時間の厳密な上限がありません。15分を超えるjobは、今回は試していません。
AWS CloudShellでECSのdescribe-tasksを実行し、撮影用に起動した1job1taskのtaskのcreatedAt、pullStartedAt、pullStoppedAt、s
図4:翌日に撮影用に1回起動したtaskの記録です。表の6件とは別のtaskで、作成からimageの取得開始まで約17秒、取得に約5秒でした。exit codeは0です。時刻はUTCです。

処理中のworkerを止めてみる

常駐workerのtaskは、deployでの入れ替えや台数を減らすときのほか、AWSの保守でも止まります(Fargateのtask retirement )。今回は、StopTaskで、SIGTERMから強制終了までの手順を試しました。ECSはcontainerへSIGTERMを送り、stopTimeoutを過ぎても終わらなければ、SIGKILLで強制終了します(StopTask )。
workerはSIGTERMを受けると、新しいjobを受け取りません。処理中のjobは、続けるか手放すかを、jobごとに指定できるようにしました。手放すときは可視性timeoutを0にして、他のworkerがすぐ受け取れるようにします(SQSの可視性timeout )。
PCで処理中を確認してから約2秒後に、そのworkerを止めました。40秒のjobでは、もう1台のworkerを先に起動して待たせています。3つの条件を、各1回試しました。
jobworkerの扱い結果exit code停止の要求から2回目の試行の確認まで
12秒続ける猶予の20秒内に完了0なし
40秒続ける強制終了。S3にRUNNINGが残る13757.8秒
40秒手放すINTERRUPTEDを書いて終了01.4秒
強制終了したjobのmessageは消されずに残り、可視性timeoutが切れてから別のworkerが受け取りました。PCで1回目と2回目の処理中を確認した間は59.8秒で、57.8秒の大部分は可視性timeoutの残りだと考えられます。手放した場合は、1.4秒で次のworkerに移りました(確認の間隔は0.5秒)。翌日の撮影用の実行でも、58.2秒と0.7秒でした。
この速さは、待たせていたworkerがあってのことです。worker 1台だけなら、代わりのworkerの起動を待ちます。今回、RunTaskからjobを受け取れるまでは25〜29秒でした。2台で待たせると、workerの費用は2倍になります。
AWS CloudShellで、撮影用に止めた3つの常駐workerの停止理由とexit codeを表示した画面。shot-killはexit 137、shot-releaseとshot-fitはex
図5:翌日に撮影用に3条件を1回ずつ実行した記録です。上はECSの停止理由(shot-kill・shot-release・shot-fit)とexit code、中はworkerのログ、下はstopTimeout内に終わったjob(f-shot)の記録です。
AWS CloudShellで最初の測定のS3の試行履歴を表示した画面。s-killはattempt 1のRUNNINGの後、別のworkerがreceiveCount 2のattempt 2でSUC
図6:2026-10-09の試行履歴です。強制終了された場合も、手放した場合も、2回目は別のworkerが受け取って成功しました。
手放すと再試行は早くなりますが、jobは最初からやり直しです。今回の2回目も、40秒すべてを処理しました。同じjobが2回動いても、結果が重ならない作りが要ります。SQSのStandard queueも、同じmessageを2回以上届けることがあります。
AWSが行うのは、SIGTERMを送り、猶予の後に止めるところまでです。続けるか、手放すか、RUNNINGのまま残ったjobをどう見つけるかは、利用者が決めます。#03でLambdaの同期Invokeがtimeoutしたときも、S3にRUNNINGが残りました。

処理中にLambdaの設定を変えてみる

Lambdaでは、deployにあたる関数の更新を、処理中に行いました。AWSの説明では、更新の間も関数はActiveのままで、呼び出しは更新が終わるまで以前のcodeと設定を使います(関数の状態 )。
20秒のjob(u-1)の処理中に、環境変数を1つ足しました。更新は1.6秒で終わり、u-1は同じ実行環境のまま続いて成功しました。停止の処理を書かなくても、処理中のjobは最後まで動きました(1回の観測)。
u-1の処理中に送ったu-2は、新しい実行環境で動きました。1つの実行環境は、同時に1件しか処理しないためです(Lambdaのscaling )。続くu-3は、u-2と同じ実行環境を使いました。設定の変更で実行環境が入れ替わるかは、分けて測れていません。
AWS CloudShellで、関数の環境変数LAB_CONFIG_MARKがupdate-1、更新がSuccessfulであることと、u-1、u-2、u-3の実行環境IDと件数、3件のREPORTを
図7:設定を変えた前後の3件です。u-1は同じ実行環境で成功しました。u-2とu-3は、u-1とは別の、同じ実行環境で動きました。

コストを比べてみる

課金の仕組みが違います。Decision Guideによると、Lambdaはrequestの数と実行時間に課金され、使われていない待機の時間には課金されません。新しい実行環境の初期化の時間も、課金に入ります(INITの課金 )。Fargateは、imageの取得を始めてからtaskが終わるまでを秒単位で課金し、最低1分です(Fargateの料金 )。
測定でも、この違いが出ました。比較の18件のLambdaのBilled Durationは、合計48.9秒でした。常駐workerは、imageの取得開始から停止まで約520秒で、そのうちjobの処理は19件で59秒でした。残りのほとんどは、測定の合間のjob待ちです。
AWS CloudShellで、比較の時間帯にあたる18件のREPORTのBilled Duration合計48879 msと、常駐worker 54e76659のログのstartとexitの時刻、S
図8:Lambdaの比較18件のBilled Durationの合計と、常駐workerのログの最初と最後の時刻、処理したjobの件数です。workerの約520秒は、2026-10-09に保存したDescribeTasksの記録から求めました。
同じ条件で、月額に直しました。jobは今回の2.5秒(Billed Durationの中央値2.701秒)、Lambdaは512 MB、workerは0.25 vCPU・512 MiBの1台です。
1時間の件数Lambdaworker 1台worker 1台(public IPv4込み)
10件約0.13ドル約9.0ドル約12.6ドル
100件約1.3ドル約9.0ドル約12.6ドル
680件約9.0ドル約9.0ドル約12.6ドル
950件約12.6ドル約9.0ドル約12.6ドル
約1,380件(1件ずつ処理するworker 1台の上限)約18.4ドル約9.0ドル約12.6ドル
workerは、件数に関係なく月約9ドルです。Lambdaは件数に比例し、1時間に約680件(public IPv4込みで約950件)を超えると高くなります。これは、1台のworkerが時間の約半分(public IPv4込みなら約7割)を、jobの処理に使う量です。
月額は730時間で計算しました。単価は、2026-10-09にPrice List APIで取得したTokyoの値です。Lambda(arm64)は1 GB秒0.0000133334 USDと100万request 0.20 USD、Fargate(ARM)は1 vCPU時0.04045 USDと1 GB時0.00442 USD、public IPv4は1時間0.005 USDです。料金表からの推計で、実際の請求額ではありません。無料利用枠、新しい実行環境の初期化(今回は0.4〜0.9秒)、SQS・ログ・NAT Gatewayの料金は入れていません。jobが重なったときの待ちと、workerを増やす費用も入れていません。

まとめ

Lambdaが合うのは、jobが間を空けて届く場合です。待っている時間に課金されず、台数の管理もAWSに任せられます。今回は、処理中に関数を更新してもjobは止まりませんでした(1回の観測)。新しい実行環境で始まるjobには、初期化が加わります。
Fargateの常駐workerが合うのは、jobが絶えず届き、1台のworkerの時間の約半分以上(public IPv4を付けるなら約7割以上)を処理に使う場合です。jobごとの初期化の待ちもありません。稼働中の同じprocessで、jobをまたいで接続やcacheを使いたい場合も候補です。15分を超えるjobは、絶えず届くなら常駐worker、間を空けて届くなら1job1taskが候補になります。jobが重なったときの待ちは、今回は測っていません。
Fargateを選ぶと、Lambdaで任せていた仕事が利用者に戻ります。taskの起動と台数、jobの受け渡し、止まるときの処理、再試行までの時間です。どちらを選んでも、jobの状態はS3のような外部に置き、同じjobが2回動いても結果が重ならない作りにします。

Series: Serverless DeepDive (13 articles)

  1. …
  2. 5
    Serverless DeepDive #04:LambdaとFargateを同じjobで比較してみる 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