Lambda のコールドスタートを減らす方法 ── プロビジョニングされた同時実行で初期化を先に済ませる
記事の「実践」を 1 項目ずつ進めるためのページです。AWS マネジメントコンソールで操作したら、右の一覧にチェックを入れてください。チェックはこのブラウザに保存されます。
前提条件
- リージョン:
ap-northeast-1(東京) - 以下のリソースが作成済みであること
まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。
| リソース種別 | リソース名 | 内容 | 作り方の参考 |
|---|---|---|---|
| Lambda 関数 | soa-coldstart-fn | Python 3.13・メモリ 128 MB・タイムアウト 15 秒。コードは下記 | AWS Lambda で関数を作成しイベント駆動で実行する |
soa-coldstart-fn の lambda_function.py は次の内容です。ハンドラーの外で 2 秒待つことで、重い初期化を再現しています。
import os
import time
# ハンドラーの外のコードは、実行環境の初期化(Init)のときに 1 回だけ動く。
# 重いライブラリの読み込みや設定の取得の代わりに 2 秒眠る
time.sleep(2)
INIT_TYPE = os.environ.get("AWS_LAMBDA_INITIALIZATION_TYPE")
def lambda_handler(event, context):
return {"initType": INIT_TYPE, "version": context.function_version}
作成するリソース一覧
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| Lambda のバージョン | 1 | プロビジョニングされた同時実行を設定する対象 |
| Lambda のエイリアス | live | バージョン 1 を指す。呼び出し側はこの名前で呼ぶ |
| プロビジョニングされた同時実行の設定 | live に 1 | 初期化済みの実行環境を 1 つ用意する |
手順 1: コールドスタートを確かめる
AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに Lambda と入力し、「Lambda」を選択して、関数 soa-coldstart-fn を開きます。
「テスト」タブで、イベント名に ping と入力し(イベント JSON はデフォルトのまま)、「テスト」をクリックします。実行結果の「詳細」を開くと、レスポンスに "initType": "on-demand" と "version": "$LATEST" が返り、「ログ出力」の REPORT 行に Init Duration: 2xxx ms が付いています。ハンドラーの実行(Duration)はわずかで、時間のほとんどが初期化に使われたことが分かります。
続けてもう一度「テスト」をクリックします。今度は同じ実行環境が再利用されるので、REPORT 行に Init Duration が付かず、すぐに応答が返ります。
手順 2: バージョンとエイリアスを作る
「バージョン」タブで「新しいバージョンを発行」をクリックし、ダイアログの「バージョンの説明 - オプション」に cold start test と入力して「発行」をクリックします(SnapStart は None のまま)。バージョン 1 が作られます。
続けて「エイリアス」タブで「エイリアスを作成」をクリックし、以下を設定して「保存」をクリックします。
- 名前:
live - バージョン:
1
手順 3: プロビジョニングされた同時実行を設定する
関数 soa-coldstart-fn の「設定」タブで、左側の「同時実行と再帰の検出」を選択します。「プロビジョニングされた同時実行」のセクションで「設定を追加」をクリックし、「プロビジョニングされた同時実行の設定」の画面で以下を設定して「保存」をクリックします。
- 修飾子のタイプ: 「エイリアス」
- エイリアス:
live - プロビジョニングされた同時実行:
1
画面には料金表へのリンクが出るだけで、金額は表示されません。この設定は保存した時点から、呼び出しの有無にかかわらず課金が始まります。
設定一覧の「ステータス」が「成功」になるまで、1〜2 分待ちます(CLI の get-provisioned-concurrency-config では IN_PROGRESS から READY に変わります)。このあいだに Lambda が実行環境を用意し、ハンドラーの外のコード(2 秒の待ち)を先に済ませています。
手順 4: エイリアスを指定した呼び出しと、関数名だけの呼び出しを比べる
上部のツールバーの CloudShell アイコンをクリックして AWS CloudShell を開き、次のコマンドを実行します。1 つ目は関数名にエイリアス live を付けた呼び出し、2 つ目は関数名だけの呼び出しです。
aws lambda invoke --function-name soa-coldstart-fn:live live.json && cat live.json; echo
aws lambda invoke --function-name soa-coldstart-fn latest.json && cat latest.json; echo
1 つ目は {"initType": "provisioned-concurrency", "version": "1"} が返り、すぐに応答します。2 つ目は {"initType": "on-demand", "version": "$LATEST"} が返ります。プロビジョニングされた同時実行は live に設定したものなので、関数名だけで呼ぶと使われません。
手順 5: ログで Init Duration を見比べる
関数の「モニタリング」タブ →「CloudWatch Logs を表示」をクリックし、ロググループ /aws/lambda/soa-coldstart-fn を開きます。ログストリーム名の [1] はバージョン 1、[$LATEST] は $LATEST の実行環境です。
ロググループの画面で「Logs Insights で表示」(または左側ナビゲーションの「Logs Insights」で、クエリの対象にロググループ /aws/lambda/soa-coldstart-fn を指定)を開き、次のクエリを実行します。
fields @timestamp, @logStream, @duration
| filter @type = "REPORT"
| parse @message "Init Duration: * ms" as initDuration
| sort @timestamp desc
[$LATEST] のストリームで最初に呼び出した行には initDuration に約 2000 が入り、[1](live 経由)の呼び出しの行には initDuration が入りません。バージョン 1 の初期化は、プロビジョニングされた同時実行を設定したときに済んでいるからです。そのときの初期化は、[1] のストリームに INIT_REPORT という別の行(Init Duration 付き)で記録されています。