この記事はコールドスタートや初回接続に要する期間を検証するものではなく、インターネット上にある情報をまとめた記事となります。
主にAWS公式の情報をメインとし、補足としてその他のブログ記事の情報を参考にしました。
コールドスタートとは
Lambdaを呼び出す際、Lambdaを実行するための環境とコードをセットアップするためのステップから開始すること。
Lambdaが初めて呼び出される際、おおまかに以下のステップがある。
- コードダウンロード
- 環境作成
- イベントハンドラー外部の初期化コード実行
- ハンドラーのコード実行
コールドスタートは、1の処理から開始することをいう。
Lambdaの実行が完了すると、Lambdaは一定期間実行環境を保持する(期間は公開されておらず、定まった期間でもない)。
環境を保持している間にLambdaが呼び出されると、Lambdaは環境を再利用できる。
このときのLambdaの実行をウォームスタートという。
ウォームスタートでは、上記の4から処理を開始するため、Lambdaの実行時間がコールドスタートと比較して速くなる。
なお、コールドスタートでLambdaが実行した後に同じLambdaを呼び出すと必ずウォームスタートになる考えてしまうが、再度コールドスタートで始まることもある。
以下のパターンがそれにあたる。
- Lambdaサービスは複数のAZにわたる高可用性サービスであり、負荷分散のため異なるAZの関数を呼び出した場合
- 関数を同時に呼び出す場合
- 並行して実行する必要があるため、同時に呼び出すたびに新しい実行環境が必要となり、コールドスタートから始まる
- Lambdaのコードや構成を変更した場合
コールドスタートを回避する方法
EventBridgeルールを使用して定期的に関数を呼び出す
関数を1分ごとに呼び出すように設定し、実行環境をアクティブに保つ。
しかし、以下の場合はコールドスタートを回避できない。
- 機能がトラフィックに合わせてスケールアップする場合
- Lambdaサービスが通常の負荷分散操作の一部として別のAZで関数を実行する場合
- Lambdaサービスは実行環境を定期的に取得して最新の状態に保つため、その場合
プロビジョニングされた同時実行性(Provisioned Concurrency)
この機能により、ウォームスタートが保たれる。
Lambdaが呼び出されるより前に、ハンドラーの実行以外の処理を終えている状態にしている(コードダウンロード、環境構築、初期化コード実行まで完了)。
例えば、Provisioned Concurrencyが6の場合、6つの実行環境が用意されていることになる。
Provisioned Concurrencyが、オンデマンド関数と異なる点は以下。
- 初期化コードの最適化は必要ない
- 呼び出しの前に初期化コードは実行されるため、呼び出しの待ち時間に影響しない
- Javaなどの初期化に時間のかかるランタイムの場合、これらのパフォーマンスはProvisioned Concurrencyを使用することで恩恵を受ける
- 初期化コードは呼び出しの総数よりも頻繁に実行される
- Provisioned Concurrencyの1つにあたり、別々のAZで1つずつ実行環境がある
- 初期化コードでログを実装している場合、このコードが実行されるたびに追加のログファイルが表示される
- LATESTバージョンでは使用できない
- 公開されているバージョンと関数のエイリアスでのみ使用可能
注意点として、Provisioned Concurrencyを使用しても、全てのLambda関数が必ずウォームスタートで開始するわけではない。
Provisioned Concurrencyが6であり、6を超える7のリクエストが同時にあった場合、超過した 1 はコールドスタートで開始される。
初期化コードの最適化
初期化コードとは、イベントハンドラー内で呼び出されない、イベントハンドラー外の処理のこと。
初期化コードの実行はコールドスタート時に行われる。
初期化コード内で事前準備可能な時間のかかる処理を行うことで、Lambdaのウォームスタート時に実行時間短縮が見込まれる。
初期化コードは、ハンドラーコードが関数で実行を開始する前に発生する。
この初期化コードで使用されるのは、主に以下。
- ライブラリと依存関係のインポート
- 本当に必要なものをインポート
- require(aws-sdk)ではなく、require(aws-sdk/clients/dynamodb)にする
- 本当に必要なものをインポート
- 構成のセットアップ
- 他のサービスへの接続(データベースなど)
グローバルスコープ
前項と同じく、コールドスタートの際に役立つもの。
初期化コードで行うこと。
- 同じ実行環境での呼び出しで、その値でよいものはグローバル変数に
- ライブラリのインポート
- DBの接続ロジック
イベントハンドラー内で行うこと。
- DBの接続ロジックは遅延読み込みを使用し、最初の呼び出しでのみ確立する
DB接続の初回だけ時間がかかる問題
LambdaからRDSなどのDBと接続する際、初回は当然時間がかかる。
この時間を削減することはできないと思われるので、前述した通り初期化コード内で接続処理を行い、ウォームスタートではすでに接続した状態にしておく。
ただし、多くのLambdaからDBに接続する場合、DBの同時接続数に引っかかる可能性があるため、その辺りは注意が必要。
DB接続処理ではないが、初回だけ処理時間がかかる問題
この問題も初期化コードでその処理を実行することが可能であれば、ウォームスタート時には処理時間が削減できる。
参考

