Lambda 実行環境のライフサイクルを理解する
Lambda は、実行環境で関数を呼び出します。これにより、安全で分離されたランタイム環境が提供されます。実行環境は、関数の実行に必要なリソースを管理します。また、関数のランタイム、および関数に関連付けられた外部拡張機能のライフサイクルサポートも提供します。
関数のランタイムは、ランタイム API を使用して Lambda と通信します。拡張機能は、拡張機能 API を使用して Lambda と通信します。拡張機能は、Telemetry API を使用することで、関数からログメッセージとその他のテレメトリを受け取ることもできます。
Lambda 関数を作成する際に、関数に許可するメモリ容量や最大実行時間など、設定情報を指定します。Lambda はこの情報を使用して実行環境をセットアップします。
関数のランタイムと各外部拡張機能は、実行環境内で実行されるプロセスです。アクセス許可、リソース、認証情報、および環境変数は、関数と拡張機能の間で共有されます。
Lambda 実行環境のライフサイクル
各フェーズは、ランタイムと、登録されているすべての拡張機能に Lambda を送信するイベントから始まります。ランタイムと各拡張機能は、Next
API リクエストを送信することで完了を示します。Lambda は、ランタイムと各拡張機能が完了して保留中のイベントがなくなると、実行環境をフリーズします。
初期化フェーズ
Init
フェーズでは、Lambda は次の 3 つのタスクを実行します。
-
すべての拡張機能を起動する (
Extension init
) -
ランタイムをブートストラップする (
Runtime init
) -
関数の静的コード (
Function init
) を実行する -
任意の before-checkpoint ランタイムフックを実行する (Lambda SnapStart のみ)
この Init
フェーズは、ランタイムとすべての拡張機能が Next
API リクエストを送信して準備完了を示したときに終了します。Init
フェーズは 10 秒に制限されています。3 つのタスクすべてが 10 秒以内に完了しない場合、Lambda は最初の関数呼び出し時に、設定された関数タイムアウトで Init
フェーズを再試行します。
Lambda SnapStart がアクティブ化されると、関数バージョンの発行時に Init
フェーズが開始されます。Lambda は、初期化された実行環境のメモリとディスク状態のスナップショットを保存し、暗号化されたスナップショットを永続化して、低レイテンシーアクセスのためにスナップショットをキャッシュします。チェックポイント前のランタイムフックがある場合、コードは Init
フェーズの最後に実行されます。
注記
10 秒のタイムアウトは、プロビジョニングされた同時実行または SnapStart を使用している関数には適用されません。プロビジョニングされた同時実行関数と SnapStart 関数の場合、初期化コードは最大 15 分間実行できます。制限時間は 130 秒、または設定されている関数のタイムアウト (最大 900 秒) のいずれか長い方です。
プロビジョニング済み同時実行を使用する場合、関数の PC 設定を行う際、Lambda は実行環境を初期化します。また Lambda は、初期化された実行環境が呼び出し前に常に使用できるようにします。関数の呼び出しフェーズと初期化フェーズの間に予期しないギャップが発生する場合があります。関数のランタイムとメモリ設定によっては、初期化された実行環境での最初の呼び出しでレイテンシーの変動が発生する場合があります。
オンデマンド同時実行を使用する関数の場合、Lambda は呼び出しリクエストの前に実行環境を初期化することがあります。これが発生すると、関数の初期化フェーズと呼び出しフェーズの間に時間のギャップが発生することがあります。この動作に依存しないことをお勧めします。
初期化フェーズ中の失敗
Init
フェーズ中に関数がクラッシュするかタイムアウトすると、Lambda は INIT_REPORT
ログにエラー情報を出力します。
例 — タイムアウトの INIT_REPORT ログ
INIT_REPORT Init Duration: 1236.04 ms Phase: init Status: timeout
例 — 拡張が失敗したときの INIT_REPORT ログ
INIT_REPORT Init Duration: 1236.04 ms Phase: init Status: error Error Type: Extension.Crash
Init
フェーズが成功した場合、SnapStart がアクティブ化されていない限り、Lambda は INIT_REPORT
ログを生成しません。SnapStart 関数は常に INIT_REPORT
を生成します。詳細については、「Lambda SnapStart のモニタリング」を参照してください。
復元フェーズ (Lambda SnapStart のみ)
SnapStart 関数を初めて呼び出し、その関数がスケールアップすると、Lambda は関数をゼロから初期化するのではなく、永続化されたスナップショットから新しい実行環境を再開します。afterRestore()
ランタイムフックがある場合、コードは Restore
フェーズの最後に実行されます。ユーザーには、afterRestore()
ランタイムフックの所要時間分の料金が請求されます。タイムアウト制限 (10 秒) 内にランタイム (JVM) がロードされ、afterRestore()
ランタイムフックが完了される必要があります。その時間を超えると、SnapStartTimeoutException が発生します。Restore
フェーズが完了すると、Lambda が関数ハンドラーを呼び出します (呼び出しフェーズ)。
復元フェーズ中の失敗
Restore
フェーズが失敗した場合、Lambda は RESTORE_REPORT
ログにエラー情報を出力します。
例 — タイムアウトの RESTORE_REPORT ログ
RESTORE_REPORT Restore Duration: 1236.04 ms Status: timeout
例 — ランタイムフック障害の RESTORE_REPORT ログ
RESTORE_REPORT Restore Duration: 1236.04 ms Status: error Error Type: Runtime.ExitError
RESTORE_REPORT
ログの詳細については、「Lambda SnapStart のモニタリング」を参照してください。
呼び出しフェーズ
Next
API リクエストに応答して Lambda 関数が呼び出されると、Lambda はランタイムと各拡張機能に Invoke
イベントを送信します。
関数のタイムアウト設定は、Invoke
フェーズ全体の所要時間を制限します。例えば、関数のタイムアウトを 360 秒に設定した場合、関数とすべての拡張機能は 360 秒以内に完了する必要があります。独立した呼び出し後フェーズはないことに注意してください。所要時間は、すべての呼び出し時間 (ランタイム + 拡張機能) の合計であり、関数とすべての拡張機能の実行が終了するまで計算されません。
呼び出しフェーズはランタイム後に終了し、すべての拡張機能は Next
API リクエストを送信して、完了したことを示します。
呼び出しフェーズ中の失敗
Lambda 関数が Invoke
フェーズ中にクラッシュするかタイムアウトすると、Lambda は実行環境をリセットします。次の図は、呼び出しに失敗した場合の Lambda 実行環境の動作を示しています。
前示の図では次のとおりです。
-
最初のフェーズは、エラーなしで実行される INIT フェーズです。
-
2 番目のフェーズは、エラーなしで実行される INVOKE フェーズです。
-
ある時点で、関数で呼び出しエラー (関数のタイムアウトやランタイムエラーなど) が発生したとします。INVOKE WITH ERROR というラベルの付いた 3 番目のフェーズは、このシナリオを示しています。これが発生すると、Lambda サービスはリセットを実行します。リセットは
Shutdown
イベントのように動作します。まず、Lambda はランタイムをシャットダウンし、登録された各外部拡張機能にShutdown
イベントを送信します。イベントには、シャットダウンの理由が含まれます。この環境が新しい呼び出しに使用される場合、Lambda は次の呼び出しとともに拡張機能とランタイムを再び初期化します。Lambda のリセットでは、次の初期化フェーズより前の
/tmp
ディレクトリコンテンツはクリアされないことにご注意ください。この動作は、通常のシャットダウンフェーズと一致しています。注記
AWS は現在、Lambda サービスに変更を実装しています。これらの変更により、AWS アカウント のさまざまな Lambda 関数によって出力されるシステムログメッセージとトレースセグメントの構造と内容にわずかな違いが生じる場合があります。
関数のシステムログ設定がプレーンテキストに設定されている場合、この変更は、関数の呼び出しに障害が発生した際に CloudWatch Logs でキャプチャされたログメッセージに影響します。次の例は、古い形式と新しい形式の両方でのログ出力を示しています。
これらの変更は今後数週間に実装され、中国および GovCloud リージョンを除くすべての AWS リージョンのすべての関数は、新しい形式のログメッセージとトレースセグメントを使用するように移行されます。
例 CloudWatch Logs ログ出力 (ランタイムまたは拡張機能のクラッシュ) - 旧形式
START RequestId: c3252230-c73d-49f6-8844-968c01d1e2e1 Version: $LATEST RequestId: c3252230-c73d-49f6-8844-968c01d1e2e1 Error: Runtime exited without providing a reason Runtime.ExitError END RequestId: c3252230-c73d-49f6-8844-968c01d1e2e1 REPORT RequestId: c3252230-c73d-49f6-8844-968c01d1e2e1 Duration: 933.59 ms Billed Duration: 934 ms Memory Size: 128 MB Max Memory Used: 9 MB
例 CloudWatch Logs ログ出力 (関数タイムアウト) - 旧形式
START RequestId: b70435cc-261c-4438-b9b6-efe4c8f04b21 Version: $LATEST 2024-03-04T17:22:38.033Z b70435cc-261c-4438-b9b6-efe4c8f04b21 Task timed out after 3.00 seconds END RequestId: b70435cc-261c-4438-b9b6-efe4c8f04b21 REPORT RequestId: b70435cc-261c-4438-b9b6-efe4c8f04b21 Duration: 3004.92 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 33 MB Init Duration: 111.23 ms
CloudWatch Logs の新しい形式には、
REPORT
行にstatus
フィールドが追加で含まれます。ランタイムまたは拡張機能のクラッシュの場合、REPORT
行にErrorType
フィールドも含まれます。例 CloudWatch Logs ログ出力 (ランタイムまたは拡張機能のクラッシュ) - 新形式
START RequestId: 5b866fb1-7154-4af6-8078-6ef6ca4c2ddd Version: $LATEST END RequestId: 5b866fb1-7154-4af6-8078-6ef6ca4c2ddd REPORT RequestId: 5b866fb1-7154-4af6-8078-6ef6ca4c2ddd Duration: 133.61 ms Billed Duration: 133 ms Memory Size: 128 MB Max Memory Used: 31 MB Init Duration: 80.00 ms Status: error Error Type: Runtime.ExitError
例 CloudWatch Logs ログ出力 (関数タイムアウト) - 新形式
START RequestId: 527cb862-4f5e-49a9-9ae4-a7edc90f0fda Version: $LATEST END RequestId: 527cb862-4f5e-49a9-9ae4-a7edc90f0fda REPORT RequestId: 527cb862-4f5e-49a9-9ae4-a7edc90f0fda Duration: 3016.78 ms Billed Duration: 3016 ms Memory Size: 128 MB Max Memory Used: 31 MB Init Duration: 84.00 ms Status: timeout
-
4 番目のフェーズは、呼び出しが失敗した直後の INVOKE フェーズを表します。ここで、Lambda は INIT フェーズを再実行して環境を再び初期化します。これは、抑制された初期化と呼ばれます。抑制された初期化が発生した場合、Lambda は CloudWatch Logs で追加の INIT フェーズを明示的にレポートしません。代わりに、REPORT 行の期間に追加の INIT 期間 + INVOKE 期間が含まれる場合があります。例えば、CloudWatch で次のログが表示されたとします。
2022-12-20T01:00:00.000-08:00 START RequestId: XXX Version: $LATEST 2022-12-20T01:00:02.500-08:00 END RequestId: XXX 2022-12-20T01:00:02.500-08:00 REPORT RequestId: XXX Duration: 3022.91 ms Billed Duration: 3000 ms Memory Size: 512 MB Max Memory Used: 157 MB
この例では、REPORT タイムスタンプと START タイムスタンプの差は 2.5 秒です。これは、報告された 3022.91 ミリ秒の期間とは一致しません。なぜなら、Lambda が実行した追加の INIT (抑制された init) が考慮されていないからです。この例では、実際の INVOKE フェーズでは 2.5 秒かかったと推測できます。
この動作に関するより多くのインサイトを得るために、Telemetry API を使用して拡張機能のリアルタイムテレメトリデータにアクセスする を使用できます。Telemetry API は、抑制された初期化が呼び出しフェーズの間で発生するたびに、
phase=invoke
のINIT_START
、INIT_RUNTIME_DONE
、およびINIT_REPORT
イベントを発行します。 -
5 番目のフェーズは、エラーなしで実行される SHUTDOWN フェーズを表します。
シャットダウンフェーズ
Lambda は、ランタイムをシャットダウンしようとする際、Shutdown
イベントを登録された各外部拡張機能に送信します。拡張機能は、この時間を最終的なクリーンアップタスクに使用できます。Shutdown
イベントは、Next
API リクエストに対するレスポンスです。
期間: Shutdown
フェーズ全体の上限は 2 秒です。ランタイムまたは拡張機能が応答しない場合、Lambda は通知 (SIGKILL
) によりそれを終了します。
関数とすべての拡張機能が完了した後、Lambda は別の関数の呼び出しを想定して、実行環境をしばらく維持します。ただし、Lambda は数時間ごとに実行環境を終了し、ランタイムの更新とメンテナンスを許可します。継続的に呼び出される関数であっても、この終了は発生します。実行環境が無期限に保持されると想定すべきではありません。詳細については、「関数にステートレスを実装する」を参照してください。
関数が再び呼び出されると、再利用のため、Lambda によって環境が解凍されます。実行環境の再利用には、次のような意味があります。
-
関数ハンドラーメソッドの外部で宣言されたオブジェクトは、初期化されたままとなり、関数が再度呼び出されると追加の最適化を提供します。例えば、Lambda 関数がデータベース接続を確立する場合、連続した呼び出しでは接続を再確立する代わりに元の接続が使用されます。新しい接続を作成する前に、接続が存在するかどうかを確認するロジックをコードに追加することをお勧めします。
-
各実行環境は、
/tmp
ディレクトリに 512 MB と 10,240 MB 間を 1 MB 刻みで提供します。ディレクトリのコンテンツは、実行環境が停止された際に維持され、複数の呼び出しに使用できる一時的なキャッシュを提供します。キャッシュに保存したデータが存在するかどうかを確認するための追加コードを追加できます。デプロイのサイズ制限の詳細については、「Lambda クォータ」を参照してください。 -
Lambda 関数によって開始され、関数が終了したときに完了しなかったバックグラウンドプロセスまたはコールバックは、Lambda 関数が実行環境を再利用したときに再開します。コードのバックグラウンド処理またはコールバックは、コード終了までに完了させてください。
関数にステートレスを実装する
Lambda 関数コードを記述するときは、実行環境が 1 回の呼び出しに対してのみ存在すると仮定して、実行環境をステートレスとして扱います。Lambda は、継続的に呼び出される関数であっても、実行時の更新とメンテナンスを可能にするために、数時間ごとに実行環境を終了します。関数の起動時に、必要な状態 (Amazon DynamoDB テーブルからショッピングカートを取得するなど) を初期化します。終了する前に、Amazon Simple Storage Service (Amazon S3)、DynamoDB、Amazon Simple Queue Service (Amazon SQS) などの永続的なデータ変更を永続的なストアにコミットします。カウンターや集計など、複数の呼び出しにまたがる既存のデータ構造、一時ファイル、または状態に依存しないようにしてください。これにより、関数は各呼び出しを個別に処理できるようになります。