- AWS
Lambdaコールドスタート対策|SnapStartとプロビジョンド同時実行の比較
コールドスタートは、Lambda が新しい実行環境を用意するときにかかる時間です。 コードのダウンロード、ランタイムの起動、ハンドラの外のコード(import・クライアントの作成)の実行が含まれます。AWS のドキュメントでは、コールドスタートは呼び出しの 1% 未満で起き、長さは 100 ミリ秒未満から 1 秒超まで幅があるとされています。
対策は「初期化そのものを軽くする」と「初期化を前もって済ませておく」の2種類です。 後者が SnapStart とプロビジョンド同時実行です。
| 対策 | 効く原因 | 追加の費用 | 向いている場面 |
|---|---|---|---|
| import を減らす・遅らせる | 大きなライブラリの読み込み | なし | まず最初に見直す |
| クライアントをハンドラの外で作る | 呼び出しのたびの作成 | なし | ほぼすべての関数 |
| メモリを増やす | CPU を使う初期化 | 実行単価が上がる | import や JIT が重い関数 |
| パッケージを小さくする(バンドル・不要物削除) | 読み込むファイルの量 | なし | Node.js・依存の多い関数 |
| SnapStart | 初期化全体(スナップショットから復元) | Java はなし。Python・.NET は保存と復元に料金 | Java・Python 3.12 以降・.NET 8 以降 |
| プロビジョンド同時実行 | 初期化全体(環境を常に待機) | 待機している時間の分 | 遅延を一定にしたい API、言語を問わない |
確認環境:Python 3.11(boto3 1.43.111・pandas)、Node.js 22.22.2(AWS SDK for JavaScript v3 3.1149.0・esbuild)、Linux(Intel Xeon 2.10GHz、計測は CPU 1 コアに固定)。初期化の時間は、AWS が公開しているランタイムクライアント awslambdaric 4.2.0 を、Lambda の Runtime API を模したサーバーにつないで測りました。SnapStart のランタイムフック(snapshot-restore-py 1.0.0)は、同じランタイムクライアントで呼ばれる順番を確かめました。CLI は AWS CLI 1.46.1 を moto 5.2.4(AWS を模したサーバー)に向けて、関数・バージョン・エイリアスの作成と Application Auto Scaling の設定が通ることを確かめ、moto が扱わないプロビジョンド同時実行の API は botocore の Stubber でパラメータを検査しました。Lambda 上の実際の Init Duration・SnapStart の効果・料金・制約は、AWS のドキュメントと料金ページに基づいて書いています(確認日 2026年10月12日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Lambdaコールドスタート対策|SnapStartとプロビジョンド同時実行の比較」
コールドスタートの仕組み:Init フェーズ
Lambda の実行環境には、大きく分けて3つの段階があります。
| 段階 | 何が起きるか | コールドスタートとの関係 |
|---|---|---|
| Init | コードのダウンロード、ランタイムの起動、ハンドラの外のコードの実行 | ここがコールドスタート |
| Invoke | ハンドラの実行 | 毎回 |
| Shutdown | 環境の終了 | — |
一度作られた実行環境は、次の呼び出しで使い回されます(ウォームスタート)。 このときは Init が起きず、ハンドラだけが動きます。新しい環境が必要になるのは、次のようなときです。
- しばらく呼ばれず、環境が片付けられたあと
- 同時に来た呼び出しが増え、環境を増やすとき(スケールアウト)
- コードや設定を更新した直後
ドキュメントでは、Init フェーズは 10 秒までです。超えると、最初の呼び出しのときに、関数のタイムアウトの中で Init をやり直します。プロビジョンド同時実行と SnapStart では、この 10 秒の制限はかからず、初期化に最大 15 分(130 秒か関数のタイムアウトの長いほう)まで使えます。
2025年8月1日から、ZIP でデプロイしたマネージドランタイムの関数も、Init の時間が課金の対象になりました。 それまで課金されなかった Init の時間が、Billed Duration に含まれます。初期化を軽くすることは、速さだけでなく料金にも効きます。
REPORT 行の Init Duration の読み方
CloudWatch Logs のロググループ /aws/lambda/関数名 には、呼び出しごとに REPORT 行が出ます。ドキュメントの例です。
REPORT RequestId: b70435cc-261c-4438-b9b6-efe4c8f04b21 Duration: 3004.92 ms Billed Duration: 3117 ms Memory Size: 128 MB Max Memory Used: 33 MB Init Duration: 111.23 ms
Init Duration が出ている行がコールドスタートです。 ウォームスタートの行には Init Duration がありません。
| 項目 | 意味 | コールドスタートでの見方 |
|---|---|---|
Init Duration |
Init フェーズにかかった時間 | この行だけに出る。大きいほど初期化が重い |
Duration |
ハンドラの実行時間 | 初回は接続の確立などで、2回目以降より長いことがある |
Billed Duration |
課金される時間 | 2025年8月1日以降、オンデマンドでは Init の時間も含む |
Restore Duration |
SnapStart の復元にかかった時間 | SnapStart の関数だけに出る |
Billed Restore Duration |
復元のうち課金される時間 | ランタイムの読み込みと after-restore フックの時間 |
利用者が待つ時間は、おおよそ Init Duration + Duration です。 SnapStart では、ドキュメントにある通り Restore Duration + Duration がコールドスタートの長さです。
種類ごとの出方の違い
| 関数の設定 | REPORT 行 | Init の記録 |
|---|---|---|
| オンデマンド(既定) | コールドスタートの行に Init Duration |
REPORT 行の中 |
| SnapStart | Restore Duration・Billed Restore Duration |
バージョン発行時の INIT_REPORT に Init Duration |
| プロビジョンド同時実行 | 待機中の環境で動けば Init Duration は出ない |
環境を用意するとき(JSON 形式のログの platform.initReport) |
関数の中からは、環境変数 AWS_LAMBDA_INITIALIZATION_TYPE で、どの方法で初期化されたかが分かります。ドキュメントでは provisioned-concurrency と on-demand の2つの値が説明されています。AWS のランタイムクライアント(awslambdaric)のコードでは、SnapStart のときに snap-start を見て処理を分けています。
CloudWatch Logs Insights でコールドスタートの割合を出す
filter @type = "REPORT"
| stats count(*) as invocations,
count(@initDuration) as coldStarts,
coldStarts * 100 / invocations as coldPct,
avg(@initDuration) as avgInitMs,
pct(@initDuration, 99) as p99InitMs
by bin(1h)
coldPct がコールドスタートの割合、p99InitMs が遅いほうの Init の時間です。 割合が小さく、利用者への影響も小さいなら、対策の優先度は下がります。
SnapStart の関数では、ドキュメントに次のクエリが載っています。コールドスタートと、そうでない呼び出しに分けて、待ち時間のパーセンタイルを出します。
filter @type = "REPORT"
| parse @log /\d+:\/aws\/lambda\/(?<function>.*)/
| parse @message /Restore Duration: (?<restoreDuration>.*?) ms/
| stats
count(*) as invocations,
pct(@duration+coalesce(@initDuration,0)+coalesce(restoreDuration,0), 50) as p50,
pct(@duration+coalesce(@initDuration,0)+coalesce(restoreDuration,0), 90) as p90,
pct(@duration+coalesce(@initDuration,0)+coalesce(restoreDuration,0), 99) as p99,
pct(@duration+coalesce(@initDuration,0)+coalesce(restoreDuration,0), 99.9) as p99.9
group by function, (ispresent(@initDuration) or ispresent(restoreDuration)) as coldstart
| sort by coldstart desc
ログの検索の基本は、関連記事「CloudWatch LogsのAWS CLI tail・検索・クエリ例」で扱っています。
原因と対策の一覧
| 原因 | 見分けるヒント | 対策 |
|---|---|---|
| 大きなライブラリの import | Init Duration が数百ミリ秒〜秒単位。メモリを増やすと短くなる |
使う場所でだけ import する。不要な依存を外す |
| 初期化で外部に接続している | VPC に入れた関数や、Secrets Manager などを Init で呼ぶ関数 | 接続先の応答を速くする(VPC エンドポイント)。タイムアウトを短く |
| パッケージが大きい | ZIP が大きい、node_modules をそのまま入れている |
バンドル(esbuild など)、不要なファイルを除く |
| メモリが小さく CPU が少ない | 128 MB など。Init も Duration も長い | メモリを増やす(CPU も比例して増える) |
| 言語・ランタイムの性質 | Java・.NET は JVM・JIT の起動が重い | SnapStart、クラスの読み込みを Init で済ませる |
| 呼び出しが少ない・急に増える | 開発環境や夜間。同時実行が増えた瞬間 | プロビジョンド同時実行、SnapStart |
VPC はコールドスタートの原因になるか
VPC に接続した関数のネットワーク(Hyperplane ENI)は、関数を作成・更新するときに作られます。 ドキュメントでは、作成中の関数は Pending の状態になり、Active になるまで数分かかることがあるとされています。呼び出しのたびに ENI を作るわけではありません。
ただし、14 日間呼ばれないと ENI が回収され、関数は Inactive になります。次の呼び出しは失敗し、ENI ができるまで再び Pending になります。VPC 内の関数で、Init の中で外部の API や DB に接続していると、その接続の時間が Init Duration に乗ります。外へ出られない場合の挙動は、関連記事「Task timed out afterの直し方|Lambdaタイムアウト原因別」で扱っています。
パッケージの大きさの上限
| 項目 | 上限(ドキュメント) |
|---|---|
| ZIP(API・SDK でアップロード) | 50 MB(それより大きいものは S3 経由) |
| ZIP の展開後(レイヤー・カスタムランタイムを含む) | 250 MB |
| コンテナイメージ | 10 GB(展開後、全レイヤー合計) |
| レイヤーの数 | 5 |
手元で測った:import と初期化の時間
ランタイムクライアント awslambdaric を、Lambda の Runtime API を模したサーバーにつないで、実際の Lambda と同じ流れ(プロセスの起動 → ハンドラの読み込み → 呼び出し)で測りました。CPU 1 コアに固定し、それぞれ 7 回の中央値です。Lambda の 128 MB はこれより CPU が少ないため、実際の時間はもっと長くなります。 差の大きさを見るための数字です。
import の時間(Python 3.11)
| 処理 | 中央値 | 最小〜最大 |
|---|---|---|
import json |
6.8 ms | 6.3〜12.0 ms |
import requests |
93.2 ms | 89.4〜156.9 ms |
import numpy |
57.7 ms | 56.2〜66.4 ms |
import boto3 |
134.1 ms | 127.2〜148.4 ms |
import pandas(numpy を含む) |
241.8 ms | 232.6〜329.5 ms |
boto3.client("s3") の作成(import 後) |
86.2 ms | 77.3〜92.5 ms |
boto3.client("dynamodb") の作成 |
56.6 ms | 48.4〜71.8 ms |
| 2つ目のクライアント(s3 の後に sqs) | 4.6 ms | 4.2〜5.0 ms |
boto3 は、import とクライアント1つの作成で、合わせて約 220 ミリ秒かかりました。 2つ目以降のクライアントは数ミリ秒です。サービスの定義ファイルの読み込みが、最初の1回に集中しているためです。
python -X importtime -c "import boto3" で内訳を見ると、s3transfer(約 76 ms)と botocore.compat が大きな割合を占めていました。
python -X importtime -c "import boto3" 2>&1 | sort -t'|' -k2 -n | tail -5
ハンドラの外で作るか、中で作るか
同じ処理(S3 のクライアントを作って使う)を、3通りの書き方で比べました。
| 書き方 | Init(起動から最初の待ち受けまで) | 1回目の呼び出し | 2回目の呼び出し |
|---|---|---|---|
| 何もしない関数(基準) | 46.1 ms | 0.8 ms | 0.6 ms |
| ハンドラの外で import・クライアント作成 | 276.9 ms | 0.7 ms | 0.5 ms |
| ハンドラの中で import・クライアント作成 | 39.0 ms | 211.2 ms | 10.1 ms |
ハンドラの中で作ると、2回目以降も毎回 約 10 ミリ秒かかりました。 import は2回目から済んでいますが、クライアントの作成が毎回やり直されるためです。ハンドラの外で作れば、ウォームスタートでは 1 ミリ秒未満です。
コールドスタートだけを見ると、どちらも合計は同じくらいです。違いは、ウォームスタートの呼び出しが毎回軽くなるかどうかです。 加えて、SnapStart とプロビジョンド同時実行は「Init で済ませた処理」を前もって片付ける仕組みなので、外で作っておくほど効果が出ます。
使わない import を遅らせる
一部の分岐でしか使わない大きなライブラリは、使う場所で import すると、Init が短くなります。
| 書き方 | Init の中央値 |
|---|---|
| ファイルの先頭で boto3 と pandas を import | 436.7 ms |
| 先頭は boto3 だけ、pandas は使う分岐の中で import | 308.6 ms |
import boto3
s3 = boto3.client("s3") # 毎回使うものは外で作る
def handler(event, context):
if event.get("report"):
import pandas as pd # レポートを作るときだけ読み込む(2回目以降は読み込み済み)
df = pd.DataFrame(event["rows"])
return {"rows": len(df)}
return {"ok": True}
この書き方は、pandas を使う呼び出しの1回目に、その分の時間が乗ります。 毎回使うライブラリは、ハンドラの外で import するほうが速くなります。
Node.js:バンドルするかどうか
AWS SDK for JavaScript v3 の S3 クライアントを使う関数で、node_modules から読み込む場合と、esbuild で1ファイルにまとめた場合を比べました(各 7 回の中央値)。
| 書き方 | 読み込みの時間 | 大きさ |
|---|---|---|
node_modules から読み込む(ESM) |
250.9 ms(192.4〜292.4 ms) | @aws-sdk と @smithy で約 24.5 MB |
| esbuild でバンドル・圧縮(CJS) | 138.2 ms(125.7〜163.9 ms) | 564,672 バイト(ZIP で 166,280 バイト) |
npx esbuild index.mjs --bundle --platform=node --target=node22 \
--format=cjs --minify --outfile=dist/index.js
手元では、--format=esm で出力すると Dynamic require of "node:https" is not supported で読み込みに失敗しました。ESM で出したいときは、esbuild の banner で require を用意するなどの対応が要ります。
ハンドラの外で初期化するコード
Python
import json
import os
import boto3
from botocore.config import Config
# Init フェーズで1回だけ動く。ウォームスタートでは使い回される
CFG = Config(connect_timeout=2, read_timeout=5, retries={"total_max_attempts": 3, "mode": "standard"})
TABLE = boto3.resource("dynamodb", config=CFG).Table(os.environ["TABLE_NAME"])
S3 = boto3.client("s3", config=CFG)
_settings = None # 遅延読み込みする設定のキャッシュ
def get_settings():
global _settings
if _settings is None: # 最初の1回だけ取りに行く
ssm = boto3.client("ssm", config=CFG)
_settings = json.loads(ssm.get_parameter(Name="/app/settings")["Parameter"]["Value"])
return _settings
def handler(event, context):
settings = get_settings()
item = TABLE.get_item(Key={"id": event["id"]}).get("Item")
return {"item": item, "limit": settings.get("limit")}
Node.js(AWS SDK v3)
// index.mjs
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand } from "@aws-sdk/lib-dynamodb";
// Init フェーズで1回だけ作る
const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({}));
const TABLE = process.env.TABLE_NAME;
export const handler = async (event) => {
const res = await ddb.send(new GetCommand({ TableName: TABLE, Key: { id: event.id } }));
return { item: res.Item ?? null };
};
手元では、DynamoDBClient と DynamoDBDocumentClient の import が 158.3 ms、クライアントの作成が 8.3 ms でした(中央値)。
Java
Java では、static フィールドや static ブロックに置いた処理が Init で動きます。AWS のドキュメントでは、重いクラスの読み込みをハンドラの外へ出すことが勧められています。
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import java.util.Map;
public class Handler implements RequestHandler<Map<String, String>, String> {
// Init フェーズで1回だけ作る(SnapStart ではスナップショットに含まれる)
private static final DynamoDbClient DDB = DynamoDbClient.builder()
.httpClient(UrlConnectionHttpClient.builder().build())
.build();
private static final String TABLE = System.getenv("TABLE_NAME");
@Override
public String handleRequest(Map<String, String> input, Context context) {
var res = DDB.getItem(GetItemRequest.builder()
.tableName(TABLE)
.key(Map.of("id", AttributeValue.fromS(input.get("id"))))
.build());
return res.hasItem() ? res.item().toString() : "not found";
}
}
この Java のコードは、AWS SDK for Java 2.x の書き方に沿った例です。
SnapStart:対応言語と制約
SnapStart は、バージョンを発行するときに Init を済ませ、その状態(メモリとディスク)をスナップショットとして保存する機能です。 新しい環境はスナップショットから復元されるので、Init をやり直しません。
対応ランタイム(2026年10月12日時点のドキュメント)
| ランタイム | 対応 |
|---|---|
| Java | Java 11 以降 |
| Python | Python 3.12 以降 |
| .NET | .NET 8 以降(Lambda Annotations を使うなら Amazon.Lambda.Annotations 1.6.0 以降) |
| Node.js・Ruby など他のマネージドランタイム | 非対応(例:nodejs24.x・ruby4.0) |
OS 専用ランタイム(provided.*) |
非対応 |
制約
| 項目 | 内容(ドキュメント) |
|---|---|
| 併用できない機能 | プロビジョンド同時実行、Amazon EFS、Amazon S3 Files、512 MB を超えるエフェメラルストレージ(/tmp) |
| 使えるバージョン | 発行したバージョンと、それを指すエイリアスだけ。$LATEST には効かない |
| リージョン | 商用リージョンのうち、アジアパシフィック(ニュージーランド)と(台北)以外 |
| 発行中の状態 | スナップショットを作る間、そのバージョンは Pending。呼び出しは失敗する |
| 復元の時間制限 | ランタイムの読み込みと after-restore フックは 10 秒以内。超えると SnapStartTimeoutException |
| 料金 | Java はなし。Python・.NET は、スナップショットの保存(最低 3 時間)と復元ごとに料金 |
スナップショットで気をつけること
1つのスナップショットから、多くの実行環境が復元されます。 Init で作った値は、全部の環境で同じになります。
| 気をつけること | 理由 | 対処 |
|---|---|---|
| Init で作った一意な ID・乱数の種 | すべての環境で同じ値になる | ハンドラの中か after-restore フックで作る |
| ホスト名を環境の識別に使う | 全環境で同じホスト名が返る | 同上 |
| Init で張ったネットワーク接続 | 復元後に使える保証がない | ハンドラか after-restore フックで張り直す |
| Java の DNS キャッシュ | 別の DNS キャッシュを使うと、復元後の接続がタイムアウトすることがある | networkaddress.cache.ttl を 0 に |
Python のランタイムフック
Python のマネージドランタイムには、snapshot_restore_py が含まれています。スナップショットの前と、復元の後に動く関数を登録できます。
import uuid
import boto3
from snapshot_restore_py import register_before_snapshot, register_after_restore
s3 = boto3.client("s3") # Init で作る(スナップショットに入る)
env_id = None
@register_before_snapshot
def warm_up():
# 例:モデルや設定ファイルを /tmp に置いておく(/tmp もスナップショットに入る)
pass
@register_after_restore
def refresh():
global env_id
env_id = str(uuid.uuid4()) # 復元のたびに作り直す
def lambda_handler(event, context):
return {"env_id": env_id}
ランタイムクライアント awslambdaric で、SnapStart の流れ(AWS_LAMBDA_INITIALIZATION_TYPE=snap-start)を動かすと、次の順番で呼ばれました。
init: import と client 作成
before_snapshot: 温めておく処理
after_restore: 一意な値を作り直す
handler: env_id=set
ランタイムクライアントは、before-snapshot フックを動かしたあと、Runtime API の /runtime/restore/next を呼んで待ち、復元されたら after-restore フックを動かしてから、通常の呼び出しの待ち受けに入ります。
SnapStart を有効にする CLI
# 1. SnapStart を有効にする(発行するバージョンに効く)
aws lambda update-function-configuration \
--function-name my-function \
--snap-start ApplyOn=PublishedVersions
# 2. バージョンを発行する(ここで Init とスナップショット作成が走る)
aws lambda publish-version --function-name my-function
# 3. 状態を確かめる
aws lambda get-function-configuration --function-name my-function:1 \
--query '{SnapStart: SnapStart, State: State}'
# 4. エイリアスを向けて、呼び出し元はエイリアスを使う
aws lambda update-alias --function-name my-function --name live --function-version 1
ドキュメントでは、OptimizationStatus が On、State が Active なら、スナップショットが使える状態です。ApplyOn に指定できるのは PublishedVersions と None です(botocore のサービス定義で確認)。
プロビジョンド同時実行:設定と注意
プロビジョンド同時実行は、指定した数の実行環境を、初期化済みの状態で待機させる機能です。 待機中の環境で動く呼び出しには、コールドスタートが起きません。言語を問わず使えます。
# エイリアス live に 5 つの環境を用意する
aws lambda put-provisioned-concurrency-config \
--function-name my-function \
--qualifier live \
--provisioned-concurrent-executions 5
# 準備ができたか確かめる(Status が READY になる)
aws lambda get-provisioned-concurrency-config \
--function-name my-function --qualifier live
# 止めるとき
aws lambda delete-provisioned-concurrency-config \
--function-name my-function --qualifier live
ドキュメントの出力例では、設定した直後は "Status": "IN_PROGRESS"・Allocated が 0 です。--provisioned-concurrent-executions は 1 以上です(botocore のサービス定義の最小値)。
| 注意点 | 内容(ドキュメント) |
|---|---|
$LATEST には設定できない |
バージョンかエイリアスに設定する |
| 呼び出し元がエイリアスを使っていない | 待機中の環境が使われず、コールドスタートが続く。API Gateway やイベントソースの向き先を確かめる |
| 上限を超えた分 | 待機中の環境が足りないと、通常の(オンデマンドの)環境で動く |
| 設定できる上限 | アカウントの予約されていない同時実行数から 100 を引いた数まで |
| 環境の入れ替え | 待機中の環境も定期的に作り直され、そのたびに Init が動く |
時間帯で増減させる(Application Auto Scaling)
# 増減させる範囲を登録する
aws application-autoscaling register-scalable-target \
--service-namespace lambda \
--resource-id function:my-function:live \
--scalable-dimension lambda:function:ProvisionedConcurrency \
--min-capacity 1 --max-capacity 20
# 平日 9 時(日本時間)に 10、20 時に 1 にする
aws application-autoscaling put-scheduled-action \
--service-namespace lambda \
--resource-id function:my-function:live \
--scalable-dimension lambda:function:ProvisionedConcurrency \
--scheduled-action-name weekday-morning \
--schedule "cron(0 9 ? * MON-FRI *)" --timezone "Asia/Tokyo" \
--scalable-target-action MinCapacity=10,MaxCapacity=20
aws application-autoscaling put-scheduled-action \
--service-namespace lambda \
--resource-id function:my-function:live \
--scalable-dimension lambda:function:ProvisionedConcurrency \
--scheduled-action-name weekday-night \
--schedule "cron(0 20 ? * MON-FRI *)" --timezone "Asia/Tokyo" \
--scalable-target-action MinCapacity=1,MaxCapacity=1
使用率に合わせて増減させるなら、ドキュメントにあるターゲット追跡のポリシーを使います。
aws application-autoscaling put-scaling-policy \
--service-namespace lambda \
--scalable-dimension lambda:function:ProvisionedConcurrency \
--resource-id function:my-function:live \
--policy-name pc-utilization-70 \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{ "TargetValue": 0.7, "PredefinedMetricSpecification": { "PredefinedMetricType": "LambdaProvisionedConcurrencyUtilization" }}'
ドキュメントでは、目標値は 10%〜90% の間で指定できます。また、使用率のメトリクスは呼び出しがあるときだけ出るため、呼び出しが止まると縮小されず、料金がかかり続けることがあると注意されています。
SnapStart とプロビジョンド同時実行の比較
| 項目 | SnapStart | プロビジョンド同時実行 |
|---|---|---|
| 仕組み | 初期化済みの状態をスナップショットから復元 | 初期化済みの環境を待機させる |
| 対応言語 | Java 11+・Python 3.12+・.NET 8+ | すべてのランタイム |
| コールドスタート | 復元の時間(Restore Duration)は残る |
待機している数の範囲ではなし |
| 費用 | Java:追加なし。Python・.NET:保存と復元 | 待機している時間×メモリ |
| 設定の単位 | 発行したバージョン・エイリアス | 発行したバージョン・エイリアス |
| 併用 | できない | できない |
| 向いている場面 | 呼び出しが多く、スケールアウトの多い Java | 遅延を一定にしたい API、言語を問わない場面 |
ドキュメントには、SnapStart は呼び出しの多い関数で効果が出やすく、まれにしか呼ばれない関数では同じ効果が出ないことがある、と書かれています。 呼び出しの少ない関数で、それでも初回を速くしたいなら、プロビジョンド同時実行が候補になります。
費用の比べ方
料金ページの例(米国東部(バージニア北部)、x86)にある単価です。リージョンやアーキテクチャで単価は変わるので、使うリージョンの料金ページで確かめます。
| 項目 | 単価(料金ページの例) |
|---|---|
| オンデマンドの実行時間 | $0.0000166667 / GB 秒 |
| プロビジョンド同時実行(待機) | $0.0000041667 / GB 秒 |
| プロビジョンド同時実行の環境での実行時間 | $0.0000097222 / GB 秒 |
| リクエスト | $0.20 / 100 万件 |
| SnapStart のキャッシュ(Python・.NET) | $0.0000015046 / GB 秒(最低 3 時間) |
| SnapStart の復元(Python・.NET) | $0.0001397998 / GB |
計算の例
プロビジョンド同時実行の待機料金は「数 × メモリ(GB)× 秒数 × 単価」です。
| 例 | 計算 | 待機料金 |
|---|---|---|
| 1 GB の関数を 1 つ、30 日間ずっと待機 | 1 × 1 GB × 2,592,000 秒 × $0.0000041667 | 約 $10.80 |
| 料金ページの例:1,536 MB を 100、8 時間 | 100 × 1.5 GB × 28,800 秒 = 4,320,000 GB 秒 | $18 |
待機している環境が実際に使われる割合(使用率)が高いほど、割安になります。 上の単価では、実行時間の単価がオンデマンドより $0.0000069445 / GB 秒 安くなります。待機料金 $0.0000041667 をこの差で割ると約 0.60 です。使用率がおよそ 60% を超えると、オンデマンドだけで動かすより安くなる計算です(リクエスト料金は同じ)。
SnapStart(Python・.NET)は「保存しているバージョンの数 × メモリ × 時間」と「復元の回数 × メモリ」です。
| 例 | 計算 | 料金 |
|---|---|---|
| 1 GB のバージョンを 30 日間保存 | 1 GB × 2,592,000 秒 × $0.0000015046 | 約 $3.90 |
| 1 GB の関数で 10,000 回復元 | 10,000 × 1 GB × $0.0001397998 | 約 $1.40 |
SnapStart を有効にしたまま使わなくなったバージョンを残すと、そのバージョンの保存料金がかかり続けます。 ドキュメントでは、使わないバージョンを ListVersionsByFunction で探して DeleteFunction で消すよう案内されています。
# バージョンの一覧
aws lambda list-versions-by-function --function-name my-function \
--query 'Versions[?Version!=`$LATEST`].[Version,LastModified]' --output text
# 使わないバージョンを消す
aws lambda delete-function --function-name my-function --qualifier 3
--query の書き方は、関連記事「AWS CLI --queryの使い方|JMESPath絞り込みと出力形式」で扱っています。
メモリと CPU
Lambda の CPU は、メモリの設定に比例して割り当てられます。 ドキュメントでは、メモリは 128 MB〜10,240 MB、1,769 MB で 1 vCPU 相当です。import や JIT のように CPU を使う初期化は、メモリを増やすと短くなります。
aws lambda update-function-configuration --function-name my-function --memory-size 1024
メモリを増やすと GB 秒あたりの料金は上がりますが、実行時間が短くなれば合計は大きく変わらないこともあります。変更の前後で、REPORT 行の Init Duration・Duration・Billed Duration を比べて決めます。
定期的に呼び出して温めておく方法
EventBridge のスケジュールで数分おきに関数を呼び、環境を残しておく方法もあります。ただし、温まるのは呼び出した数の環境だけで、同時に多くの呼び出しが来たときに増える環境には効きません。また、ドキュメントでは、オンデマンドの環境が呼び出しの前に初期化されることがあっても、その挙動に頼らないよう書かれています。遅延を確実に抑えたいときは、プロビジョンド同時実行か SnapStart が、AWS の用意した方法です。
よくある質問
Q. コールドスタートはどのくらいの頻度で起きますか。 A. ドキュメントでは、呼び出しの 1% 未満とされています。開発・テストの関数は呼び出しが少ないので、本番より多く起きがちです。実際の割合は、上の Logs Insights のクエリで確かめられます。
Q. プロビジョンド同時実行を設定したのに、Init Duration が出ます。
A. 呼び出し元が、設定したエイリアス(またはバージョン)を呼んでいるか確かめます。$LATEST や別のエイリアスを呼んでいると、待機中の環境は使われません。待機の数を超えた呼び出しも、通常の環境で動きます。
Q. Node.js で SnapStart は使えますか。 A. 2026年10月12日時点のドキュメントでは、Node.js は対応していません。Node.js では、バンドルで読み込みを軽くすることと、プロビジョンド同時実行が選択肢です。
Q. SnapStart とプロビジョンド同時実行は一緒に使えますか。 A. 使えません。ドキュメントで、SnapStart はプロビジョンド同時実行に対応しないとされています。
Q. コンテナイメージの関数でも SnapStart は使えますか。 A. ドキュメントには、Lambda のベースイメージやカスタムのベースイメージで作ったコンテナイメージ向けに、SnapStart のランタイムフックを組み込む方法のページがあります。使う前に、そのページの条件を確かめます。
Lambda の関数の作り方・更新は、関連記事「AWS CLIでLambdaを作成・更新 環境変数とレイヤー」で、Python のハンドラの書き方は、関連記事「AWS Lambda Python入門|3.14対応handler例とローカルテスト」で扱っています。
まとめ
- REPORT 行に
Init Durationが出ている呼び出しがコールドスタート。SnapStart ではRestore Duration - 2025年8月1日から、ZIP・マネージドランタイムでも Init の時間が課金される
- まず import を減らす・遅らせる、クライアントはハンドラの外で作る。手元では、中で作ると毎回 約 10 ms かかった
- SnapStart は Java 11+・Python 3.12+・.NET 8+。発行したバージョンだけ。プロビジョンド同時実行・EFS とは併用不可
- プロビジョンド同時実行はエイリアスかバージョンに設定し、呼び出し元もそこを呼ぶ。料金ページの単価では、使用率 約 60% を超えるとオンデマンドより安い計算
参考・出典
確認日はいずれも 2026年10月12日です。
- AWS Lambda デベロッパーガイド「Understanding the Lambda execution environment lifecycle」:https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html
- AWS Lambda デベロッパーガイド「Improving startup performance with Lambda SnapStart」:https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html
- AWS Lambda デベロッパーガイド「Activating and managing Lambda SnapStart」:https://docs.aws.amazon.com/lambda/latest/dg/snapstart-activate.html
- AWS Lambda デベロッパーガイド「Performance tuning for Lambda SnapStart」:https://docs.aws.amazon.com/lambda/latest/dg/snapstart-best-practices.html
- AWS Lambda デベロッパーガイド「Lambda SnapStart runtime hooks for Python」:https://docs.aws.amazon.com/lambda/latest/dg/snapstart-runtime-hooks-python.html
- AWS Lambda デベロッパーガイド「Monitoring for Lambda SnapStart」:https://docs.aws.amazon.com/lambda/latest/dg/snapstart-monitoring.html
- AWS Lambda デベロッパーガイド「Configuring provisioned concurrency for a function」:https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html
- AWS Lambda デベロッパーガイド「Giving Lambda functions access to resources in an Amazon VPC」:https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html
- AWS Lambda デベロッパーガイド「Lambda quotas」:https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html
- AWS Compute Blog「AWS Lambda standardizes billing for INIT Phase」:https://aws.amazon.com/blogs/compute/aws-lambda-standardizes-billing-for-init-phase/
- AWS Lambda の料金:https://aws.amazon.com/lambda/pricing/
- awslambdaric(AWS Lambda Runtime Interface Client for Python)4.2.0:https://pypi.org/project/awslambdaric/
- snapshot-restore-py 1.0.0:https://pypi.org/project/snapshot-restore-py/
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Lambdaコールドスタート対策|SnapStartとプロビジョンド同時実行の比較」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。