最近の投稿でC#で書いたプログラムをLambdaで実行させていますが、初回実行が2回目以降と比較して明らかに遅いようなので簡単に調査しました。
構成
PCからJMeterでAPI Gatewayへリクエストし、API GatewayがLambdaをキックさせます。
- Lambda自体は定数文字列をJSON形式で返す以外に何もさせないが、ログストリームからLambdaの実行時間(Duration)をサンプリング
- Cloudwatchのログストリームの取得では下記投稿のプログラムを使わせていただきました
using Amazon.Lambda.Core; namespace AWSLambda { public class Function { [LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] public string FunctionHandler(ILambdaContext context) { return "Hello, World!"; } } }
- JMeterからは10スレッドから各10回のリクエスト(合計100リクエスト)を送信して遅延時間(elapsed)をサンプリング
- Ramp-Upが0秒(全スレッドが同時起動)のため、各スレッドの最初のリクエストでLambda10個が同時に実行開始される
- PCからAPI GatewayまでのRTTは100ms程度
結果
Lambdaの割当メモリを128MB、256MB、512MBの3パターンで計測してみた結果が、以下の表です。
128MB | 256MB | 512MB | |
---|---|---|---|
1回目のアクセス時の平均遅延時間(ms) | 5864 | 4312 | 2706 |
2回目以降のアクセス時の平均遅延時間(ms) | 1631 | 413 | 431 |
1回目の平均Lambda実行時間(ms) | 1869 | 986 | 467 |
2回目以降の平均Lambda実行時間(ms) | 110 | 1.45 | 0.92 |
- 1回目のアクセスが2回目以降のアクセスよりも明らかに時間を要し、メモリ512MBで平均2.7秒
- 単純な処理時間の増大に加えて、滞留するリクエストの増大によるLambdaの同時実行数の増加も考慮する必要があります
- 例えば100リクエスト/秒の場合、0.0秒~1.0秒の100リクエストで100個のLambdaが初回実行します
- 初回実行のため2.7秒を要すると、1.0秒~2.7秒の間に受けたリクエストはLambdaの同時実行数の上限(通常100)に達して500エラーが返されます
- 単純な処理時間の増大に加えて、滞留するリクエストの増大によるLambdaの同時実行数の増加も考慮する必要があります
- 初回実行の場合も割当メモリを増やすことで実行時間は改善されるようです
まとめ
Lambda単体での遅延時間・処理時間を計測することで、2回目以降と比較して初回実行に時間を要することを確認しました。
今回はプログラムをデプロイし直すことで初回実行を再現させていましたが、ある程度時間が経ってから実行すると初回実行と同等の時間を要するようになりますので、設計時に頭に入れておいたほうが良さそうです。