Provisioned Concurrencyで予約したLambda実行環境のライフサイクルを調べてみた #reinvent

2019.12.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CX事業本部@大阪の岩田です。Lambdaの実行環境はアクセス有無に関わらず、定期的に破棄&再生成されることが知られていますが、Provisioned Concurrencyの設定を利用してプロビジョニングした環境はどうなのでしょうか??通常のLambda実行環境と同じようなライフサイクルになるのでしょうか?気になったので調べてみました。

やること

まず以下のコードを準備します。

console.log('start initialization');

exports.handler = async (event) => {

    // TODO implement
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

デフォルトのHello Worldのコードにhandler外のログ出力を追加しただけのコードです。このLambdaのコードから新しいバージョンを発行し、発行されたバージョンにProvisioned Concurrencyを設定して放置してみます。Lambda実行環境がプロビジョニングされると、CloudWatch Logsには以下のようなログが出力されます。

2019-12-09T05:04:26.937Z undefined INFO start initialization

Provisioned Concurrency設定後にしばらく放置しておき、この出力されたログのタイムスタンプを分析してみます。

分析

ある程度ログが貯まったら今度は分析です。今回は丸3日ほど放置してログを出力しました。結果を一部抜粋するとこのような結果でした。ここでは5件のみ抜粋していますが、実際には80件程度のログが手元にあります。

タイムスタンプ
2019-12-12T13:36:58.444Z
2019-12-12T13:29:50.472Z
2019-12-12T12:13:19.222Z
2019-12-12T11:27:54.243Z
2019-12-12T11:19:39.346Z

結果をEXCELに貼り付けて、1つ手前のタイムスタンプとの差分を計算します。

タイムスタンプ 前回ログが出力されてから経過した時間
2019-12-12T13:36:58.444Z 0:07:08
2019-12-12T13:29:50.472Z 1:16:31
2019-12-12T12:13:19.222Z 0:45:25
2019-12-12T11:27:54.243Z 0:08:15
2019-12-12T11:19:39.346Z 0:57:13
2019-12-12T10:22:26.778Z 0:07:00

計算して求めた前回ログ出力以後の経過時間を分析してみます。

最大値

最大値は1時間55分25秒でした。ちょっと長く見積もってもProvisioned Concurrencyで起動したLambda実行環境の寿命は2時間程度と考えて良さそうです。

最小値

なんと、、、0秒でした。実際のログは以下のようなログでした。2019-12-12T00:59:22.490ZにLambda実行環境がプロビジョニングされた直後(134ミリ秒後)に次のLambda実行環境がプロビジョニングされていることが分かります。Provisioned Concurrencyの指定としては1つのLambda実行環境を予約しているだけですが、実際には同時に2つのLambda実行環境が起動しているタイミングが存在しそうです。

2019-12-12T00:59:22.624Z undefined INFO start initialization
2019-12-12T00:59:22.490Z undefined INFO start initialization

平均

平均を計算すると、54分17秒でした。大体1時間ぐらいですね。

中央値

中央値は45分31秒でした。こうやって見ると結構頻繁にLambda実行環境の再生成が行われているイメージですね。

Provisioned Concurrency無しのパターンと比較

これだけで終わるのも少し寂しいので、CloudWatch Eventから5分毎にProvisioned Concurrencyを設定していないLambdaを叩いて同様の分析を行いました。最終的な結果は以下の通りです。

指標 Provisioned Concurrency有り Provisioned Concurrency無し
最大値 1:55:25 2:07:52
最小値 0:00:00 0:06:42
平均値 0:54:17 1:50:52
中央値 0:45:31 2:01:46

Provisioned Concurrency無しの場合の方がLambda実行環境のライフサイクルが長いように見えますが、実際のところはどうなんでしょうね??

まとめ

Provisioned ConcurrencyでプロビジョニングしたLambda実行環境のライフサイクルについて調べてみましたが、想像していたよりもライフサイクルは短めのようです。

ライフサイクルが短ければ、それだけ攻撃を受けるリスクを低減できるので、セキュリティ面を考慮してこのような振る舞いになっているのかもしれません。そういえば確かherokuも最低1日1回はコンテナが再起動される仕様ですね。もしくは、Lambda実行環境をホストしているWorkerの負荷を平準化するために環境の停止と別Workerへの配置を行なっているのかもしれません。この辺りの裏側を考察するのは楽しいですね!