Lambda SnapStart でベンチマークをとって効果検証をしてみた
2024年11月22日に AWS Lambda の SnapStart が Python でも使えるようになっていたのですが、実際どれくらい効果があるのか気になって、ベンチマークツールを作って検証してみました。
結論から言うと、コールドスタート時間が 85% も改善しました!これはかなりインパクトがありますね。
Lambda SnapStart って何?
まず簡単に SnapStart について説明すると、Lambda のコールドスタート問題を解決するための機能です。
通常、Lambda 関数が起動するときは:
- 実行環境の準備
- ランタイムの起動
- コードのロード
- 初期化処理の実行
という手順を踏むんですが、特に Python で NumPy や Pandas みたいな重いライブラリを使うと、この初期化に数秒かかることがあります。
SnapStart は、この初期化済みの状態をスナップショットとして保存しておいて、次回起動時にそこから復元することで高速化する仕組みです。Firecracker microVM のスナップショット機能を使っているそうです。
なぜベンチマークを作ったのか
AWS のドキュメントには「大幅に改善します」と書いてあるけど、実際のところどれくらい速くなるの?という疑問がありました。
特に気になったのは:
- Python でも本当に効果があるのか?
- NumPy/Pandas みたいな重いライブラリでどれくらい改善するか?
- 追加コストに見合う効果があるか?
ということで、実際に測定できるツールを Claude Code を使って作ってみました。
以下のコードはプロンプトを3回くらい入力しただけでできてしまったので驚きですね!
ベンチマークツールの構成
作ったベンチマークツールは、同じ Lambda 関数を SnapStart あり/なしの 2 パターンでデプロイして、パフォーマンスを比較する仕組みです。
Lambda 関数の中身
テスト用の Lambda 関数はこんな感じで、あえて重い処理を入れています:
# グローバルスコープでの初期化(SnapStartで最適化される部分)
import numpy as np
import pandas as pd
import boto3
# 重いライブラリのインポートとセットアップ
df = pd.DataFrame(np.random.randn(10000, 100))
df_summary = df.describe()
# AWS SDKクライアントの初期化
s3_client = boto3.client('s3')
dynamodb_client = boto3.client('dynamodb')
ssm_client = boto3.client('ssm')
# 疑似的な機械学習モデルの初期化
class DummyModel:
def __init__(self):
self.weights = np.random.randn(1000, 1000)
self.bias = np.random.randn(1000)
# 行列演算で時間を消費
for _ in range(5):
self.weights = np.dot(self.weights, self.weights.T) / 1000
model = DummyModel()
def lambda_handler(event, context):
# ハンドラー内の処理は軽め
input_data = np.random.randn(100)
prediction = model.predict(input_data)
return {"statusCode": 200, "body": json.dumps({...})}
ポイントは、初期化処理(グローバルスコープ)に重い処理を集中させていることです。これが SnapStart で最適化される部分になります。
デプロイ構成
CloudFormation で以下の 2 つの Lambda 関数を作成します:
- SnapStart なし: 通常の Lambda 関数
-
SnapStart あり:
SnapStart: ApplyOn: PublishedVersions
を設定
# SnapStartありのLambda関数
LambdaFunctionWithSnapStart:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub '${AWS::StackName}-with-snapstart'
Runtime: python3.12
SnapStart:
ApplyOn: PublishedVersions # ← これがポイント!
# ... その他の設定
PublishedVersions は簡単に言うと、「公開されたバージョンにのみ SnapStart を適用する」 という設定値です。
Lambda の 2 つの状態
- $LATEST(最新版)
- 開発中の作業バージョン
- コード更新のたびに変わる
- SnapStart 使えない ❌ - Published Version(公開バージョン)
- 固定されたバージョン(1, 2, 3...)
- 一度公開すると変更不可
- SnapStart 使える ✅
なぜ公開バージョンのみなのか?
$LATEST の問題:
・コードが頻繁に変更される
・スナップショット作ってもすぐ無効に
・無駄なコストが発生
PublishedVersions の利点:
・コードが固定で変わらない
・スナップショットが確実に有効
・本番環境で安定して使える
つまり、SnapStart は本番環境向けの機能として設計されており、開発中の頻繁に変更されるコードではなく、固定された安定版でのみ動作するようになっているようです。
実際にベンチマークを実行してみた
セットアップ
まず環境をデプロイします:
# リポジトリをクローン
git clone https://github.com/Mo3g4u/lambda-snapstart-benchmark
cd lambda-snapstart-benchmark
# デプロイスクリプトを実行
./deploy.sh
デプロイスクリプトが自動で:
- S3 バケットを作成
- 依存関係(NumPy、Pandas)をレイヤーとしてパッケージング
- CloudFormation スタックをデプロイ
してくれます。便利!
ベンチマークテストの実行
デプロイが完了したら、ベンチマークを実行:
python benchmark_test.py \
--function-no-snapstart lambda-snapstart-benchmark-no-snapstart \
--function-with-snapstart lambda-snapstart-benchmark-with-snapstart:live \
--cold-tests 3 \
--warm-tests 5 \
--concurrency 5
このスクリプトは 3 種類のテストを実行します:
- コールドスタートテスト: 新しい実行環境での起動時間を測定
- ウォームスタートテスト: 既存の実行環境での実行時間を測定
- 同時実行テスト: 複数の同時リクエストでのパフォーマンスを測定
驚きの測定結果!
実際に測定してみた結果がこちら:
============================================================
テスト結果サマリー
============================================================
NO SNAPSTART:
コールドスタート:
平均: 2457.91ms
中央値: 2384.19ms
最小: 2358.27ms
最大: 2631.26ms
WITH SNAPSTART:
コールドスタート:
平均: 353.93ms
中央値: 56.93ms
最小: 44.93ms
最大: 959.94ms
============================================================
SnapStartによるコールドスタート改善率: 85.6%
SnapStartなし平均: 2457.91ms
SnapStartあり平均: 353.93ms
短縮時間: 2103.97ms
============================================================
結果の解釈
コールドスタート時間が 2.5 秒から 0.35 秒に短縮!
これはすごい改善ですね。特に注目したいのは:
-
初回起動(最大値 959ms)
- SnapStart ありでも初回は少し時間がかかる
- これはスナップショットの初回ロードのため
-
2 回目以降(最小値 45ms)
- キャッシュが効いて爆速に!
- ほぼウォームスタートと同じレベル
-
ウォームスタート(40-60ms)
- SnapStart の有無で差はない(予想通り)
同時実行時のパフォーマンス
同時に 5 つのリクエストを送った場合:
- SnapStart なし: 平均 124.70ms
- SnapStart あり: 平均 60.91ms
- 改善率: 51.2%
大量のトラフィックが来たときのスケーリングでも効果的ですね。
実際に使ってみた感想
良かった点
- 効果が明確: 85% の改善は期待以上でした
- 設定が簡単: CloudFormation に数行追加するだけ
- 既存コードの変更不要: 基本的にはそのまま使える
注意点
-
コストが追加でかかる(Python の場合)
- キャッシュ料金: $0.00002/GB-時間
- リストア料金: $0.0000083/リクエスト
- ただし、レスポンス改善を考えると十分ペイする
-
ユニーク性の考慮が必要
- UUID や乱数生成はハンドラー内で行う必要がある
- スナップショットが複数の実行環境で共有されるため
-
初回起動は少し遅い
- スナップショットの初回ロードに時間がかかる
- でも 2 回目以降は爆速
どんな場合に使うべき?
実際に使ってみて、以下のケースで特に効果的だと感じました:
おすすめケース ✅
- API のエンドポイント: レスポンスタイムが重要
- 不規則なトラフィック: コールドスタートが頻発する
- 重いライブラリを使用: NumPy、Pandas、機械学習ライブラリなど
- ユーザー体験重視: 2 秒の待ち時間を許容できない
あまり向かないケース ❌
- 常にウォーム: 頻繁にアクセスがある場合は不要
- バッチ処理: レスポンスタイムが重要でない
- 軽量な関数: そもそもコールドスタートが速い
まとめ
Lambda SnapStart、想像以上に効果がありました!特に Python で重いライブラリを使っている場合は、検討する価値が十分にあります。
今回作ったベンチマークツールは GitHub で公開しているので、ぜひ自分の環境でも試してみてください:
設定も簡単だし、効果も明確なので、コールドスタートに悩んでいる方はぜひ試してみることをおすすめします。
ちなみに、Java だと追加料金なしで使えるらしいので、Java ユーザーは迷わず有効化していいと思います!
Discussion