AWS Lambdaのライフサイクルを理解する!

AWS

このブログは、Cloud Partner Advent Calendar 2025の2日目の記事です。

こんにちは!クラウドパートナーの大川です

AWSでサーバーレスを実現する方法として、代表的なサービスがAWS Lambdaですね
手軽にコードを実行できますが、Lambdaがコードを実行するとき、その裏側で何が起こっているのでしょうか?

本記事ではLambdaの実行環境の初期化、実行、そしてシャットダウンという3つの主要フェーズを、初心者にもわかりやすく解説します

また、ただ概念を説明するだけでなく、AWSの分析ツールであるX-Rayを活用し、
コールドスタートの具体的な所要時間を確認してみたいと思います

AWS Lambdaの3つの主要コンポーネントを抑える

ライフサイクルの解説をする前に、Lambdaを構成する重要な要素を抑えましょう

Lambda関数は、以下の3つの主要なコンポーネントが連携して動作しています
これらのコンポーネントは、入れ子になった階層構造として捉えると分かりやすいです

  • Lambda Function (関数コード)
    • 私たちが記述するビジネスロジックそのものです
  • Runtime (ランタイム)
    • 関数コードを実行するための言語固有の環境です(例:Node.js、Python、Javaなど)
    • 関数コードと実行環境の間を取り持ち、AWSからのイベントを関数コードに渡し、結果を受け取る役割を果たします
  • Execution Environment (実行環境)
    • 最も外側の層であり、関数を実行するための基盤となる隔離された環境
      (コンテナ)です
    • メモリ、CPU、ネットワークなどのリソースを割り当て、
      ランタイムと関数コードが安全かつ安定して動作するための土台を提供します。

この要素を図にすると以下のようになります
実行環境の中にRuntimeとLambda Functionが格納されていることがわかります

実行環境の「使い回し」の仕組み

この階層構造の中で、特に重要なのが「実行環境」です
Lambdaがイベントを受け取ると、迅速に実行環境を用意して関数を実行します

しかし、イベントのたびに環境を一から作成していると、起動に時間がかかりすぎてしまいます
そこで、Lambdaは一度立ち上げた実行環境を、すぐには破棄せず、一定期間プールに保持します

次に同じ関数へのリクエストが来たとき、もしプールに待機中の環境があれば、その環境を使い回すことができます

この環境の再利用こそが、ウォームスタートと呼ばれる挙動です
Lambdaの高速な応答速度を実現する鍵となります

逆に、環境の新規作成から始めるのが、後に詳しく解説するコールドスタートです

Lambda ライフサイクルを構成する3つのフェーズ

それでは、今回の本題となります

Lambdaはユーザーから実行のリクエストを受けると、次の3つのフェーズを踏みながら処理を行います

このライフサイクルを理解しましょう

  1. Init フェーズ(初期化)
  2. Invoke フェーズ (実行)
  3. Shutdown フェーズ (終了)

図にすると以下になります

さらに、各フェーズで具体的にどのような処理をしているか見ていきましょう

①Intiフェーズで行われていること

Init(初期化)フェーズは、以下の3つのサブステップで構成され、順番に処理が行われます

  1. Extension init (エクステンション初期化)
    • 拡張機能が最初に起動し、初期設定や外部システムへの接続準備を行います
    • 拡張機能は、セキュリティエージェント、モニタリングツール、テレメトリー(監視)ツールなど、さまざまな目的で使用されます
  2. Runtime init(ランタイム初期化)
    • PythonやNode.jsといった、関数コードを実行するためのランタイムが起動し、環境をセットアップします
    • S3から関数コード設定されているすべてのレイヤーをダウンロードし、実行環境のファイルシステム上に展開します
  3. Function init (関数初期化)
    • 私たちの関数コードのグローバルスコープ(ハンドラ関数の外側)に記述されたコードが実行されます
    • データベース接続の確立、設定ファイルのロード、外部ライブラリのインポートなど、
      時間のかかる処理は通常ここで行われます

Intiフェーズの重要ポイント

  • このフェーズ全体にかかる時間が、コールドスタート時の遅延の主要な原因となります

図にすると以下の流れになります

②Invokeフェーズ

続いてInvokeフェーズを詳しくみていきましょう

Invokeフェーズは、①で行われた実行環境準備が整った後に実行され、ハンドラ関数の実行を行います

  • 内部処理
    • ランタイムがイベントデータを受け取り、それを関数コードのハンドラ関数に渡します
    • ハンドラ関数内で定義されたビジネスロジックが実行され、処理結果が呼び出し元に返されます
  • 課金対象
    • このInvokeフェーズの実行時間が、AWS Lambdaの実行時間における主要な課金対象となります

Invokeフェーズの重要ポイント:

  • 実行環境が再利用されるウォームスタートの場合、Initフェーズは完全にスキップされ、すぐにこのInvokeフェーズから処理が始まります。これによって高速な実行が可能です

③Shutdownフェーズ

最後に、Shutdownフェーズを見ていきましょう

Shutdownフェーズは、関数がInvokeフェーズの完了後、実行環境が一定時間(数分程度)アイドル状態が続いた場合に、終了処理を行います

  1. Runtime Shutdown(ランタイムの終了)
    • まずランタイムにシャットダウンシグナルが送信されます
  2. Extension Shutdown(拡張機能の終了)
    • Extensionに対してもシャットダウンシグナルが送られ、最大2秒程度の猶予時間内で、
      リソースの解放や、Invokeフェーズでバッファリングしていたログ・メトリクスの最終送信などのクリーンアップ処理を行うことができます

図にすると以下の流れになります

ライフサイクルを全体図で確認

ここまで各フェーズを見てきましたが、全体で見ると以下になります
Lambda実行のリクエストがあると、以下の順番で処理が行われます

ウォームスタートとコールドスタートの実行パターン

上記で見てきた3つのフェーズは、Lambda関数が呼び出されたときに、
「実行環境が新規に立ち上がるか」「既存の環境が再利用されるか」によって、たどる経路が変わります

この違いが、途中で名前が出ていましたがコールドスタートウォームスタートです

それぞれの実行パターンを比較してみましょう

ウォームスタート

  • パターン: 実行環境がまだプールに待機しており、再利用される場合
  • たどるフェーズ: Initフェーズを完全にスキップし、すぐに Invokeフェーズ から処理を開始します
  • 特徴: 実行環境は既に立ち上がっており、グローバルスコープのコード(DB接続など)も実行済みのため、非常に高速に応答が可能です。
    Initフェーズの時間がゼロになるため、理想的な状態と言えます

コールドスタート

  • パターン: プールに再利用できる環境がなく、AWSが新しい実行環境を立ち上げる必要がある場合
  • たどるフェーズ: Initフェーズ(Extension init、Runtime init、Function init)から始まり、
    その後 Invokeフェーズ に移行します
  • 特徴: 環境のプロビジョニングや初期化(コードのダウンロード、依存関係のロードなど)の時間が実行時間に加算されるため、応答が遅くなります。
    この遅延が、ユーザー体験に影響を与えることが良くあります

実行パターンInitフェーズの実行Invokeフェーズの実行実行速度
ウォームスタートスキップ実行高速
コールドスタート実行される実行低速

ライフサイクルとパフォーマンスの関係

このようにコールドスタートはInitフェーズで実行される処理の時間となります

したがって、Lambdaのパフォーマンスを最適化するには以下の2つが重要となります

  • 「Initフェーズの時間を可能な限り短縮する」
  • 「コールドスタートの発生自体を避ける」

動作で確認

では実際にコールドスタートとウォームスタートの挙動を確認してみましょう

以下のようなLambda関数を作成しました
またX-Rayを有効化しておきます

そして、この関数を2回実行します

import json
from datetime import datetime, timedelta, timezone

JST = timezone(timedelta(hours=+9), 'JST')
now = datetime.now(JST).strftime("%Y%m%d%H%M%S")

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Lambda! - ' + now)
    }

結果を確認

  • 1回目の結果
{
  "statusCode": 200,
  "body": "\"Lambda! - 20251212130956\""
}

  • 2回目の結果
{
  "statusCode": 200,
  "body": "\"Lambda! - 20251212130956\""
}

ご覧の通り、タイムスタンプの値が変わっていません

これは、変数nowの値が1回目の実行で代入された値(コールドスタート実行時のタイムスタンプ)を使い回しているからです

つまり2回目はウォームスタートで実行されたことが分かります

X-Rayで結果を確認

先ほどの2回の実行をX-Rayで見てみましょう

X-Rayを使うことでLambdaの実行にどれだけ時間がかかったかを確認できます

  • 1回目の結果

全体で見ると所要時間が322ミリ秒となっています

下の部分にinitという項目がありますが、これがinitフェーズにかかった時間となります

initには126ミリ秒かかっており、およそ全体処理の3分の1がinitに使われていることがわかります

  • 2回目の結果

対して2回目は、全体で見ると所要時間が44ミリ秒と、1回目の4分の1と高速になっています

さらにinitの項目が無くなっていることがわかります

これがウォームスタートとコールドスタートの違いです

まとめ

AWS Lambdaのライフサイクルとコールドスタートの具体的な仕組みについて理解を深めていただけたでしょうか?

今回の記事で、Lambdaの実行環境は「InitInvokeShutdown」という明確な3つのフェーズを踏んでおり、特に Init フェーズがコールドスタートと関係していることが、X-Rayのトレース結果からも確認できました。

お知らせ
AWS✖️GitLabを活用したアジャイル開発にご興味はありませんか?

  • 弊社では、AWS×GitLabを活用したアジャイル開発導入支援サービスを提供しています。
    GitLabの基本的な使い方から、アジャイル・スクラムの実践的な進め方までを体験的に習得することができます。詳しくはサイトをご確認ください。
    https://www.cloud-partner.jp/insource/

無料相談実施中
AWSを使用したサーバーレスアプリケーションの構築
サーバーレス開発内製化、AWSへの移行等
様々な課題について無料でご相談お受けいたします。
最新情報をチェックしよう!