AWS Lambdaには、コールドスタート時に 最大10秒間だけCPUとメモリリソースが強化される「boost host CPU」 という仕様があるのをご存知でしょうか?
Lambdaのリファクタとして、各呼び出しで共通するリソース用意の処理(S3クライアントを生成するコード)をグローバルスコープに移動したところ、なぜか処理時間が短縮されました。
「S3クライアントの初期化のタイミングが変わっただけで、全体の実行時間は変わらないだろう」と思っていたのですが、処理時間が短縮した事実から、調べるとboost host CPUという仕様の恩恵を受けていたことがわかりました。
本記事では、変更前後の処理時間の変化、boost host CPUの仕組みについて紹介します。
Lambda初心者向けの記事ですので、必要に応じて以下のトグルを展開してください。
用語の説明や環境
- 「S3クライアント」の意味
- AWS S3の操作をするためのオブジェクト
- クライアントタイプのAPI、リソースタイプのAPIは本記事では区別せずとします
- Lambdaのコールドスタートとグローバルスコープ
- コールドスタートとは、Lambdaがリクエストを処理する際に、まだ準備ができていない状態(インスタンスが存在しない状態)から新しい実行環境(コンテナ)を起動して関数コードを読み込む処理のことです
- 初回実行時や、しばらく使われていなかったときにコールドスタートとなり、この時、関数の初期化(ダウンロード)やグローバルスコープの処理が実行されます
- グローバルスコープとは、Lambda関数ファイル内で lambda_handler(エントリーポイント)の外側に書かれたコード領域を指します
- 詳細は公式をご参照ください
- Lambdaの環境
- コンテナLambdaにてRuby 3.2を指定(コンテナイメージで指定)
- メモリ:128 MB(デフォルト)
- エフェメラルストレージ:512 MB(デフォルト)
- 受け取ったイベントをS3のオブジェクトとしてputするだけの処理をするLambdaに対して以下の変更を行いました
-
ベストプラクティスに沿って、S3クライアントの生成処理をlambda_handler内ではなくグローバルスコープ側に移動しました
CloudWatchメトリクスとログで効果を観測しました。
深夜から明朝の時間帯で、”点”だけのところが比較しやすいと思います(上図赤枠)。
この点はDuration averageとmaximumが同値となる点、つまり1回だけの呼び出しの記録点であることを意味し、初期化を伴う呼び出しとなったことを表す点です(CloudWatchログでも確認済み)。
Duration maximum、この場合はつまり初期化を伴う実行時間が、4−5秒減少したことがわかりました!
CloudWatchログから拾った結果を下表の通りまとめました。
- ()内は実測値が普遍的であると仮定した場合の想定値です(正確な実測は端折りました)
- なお、Init Durationの値は、解釈を簡単にするため、グローバルスコープの処理時間であると考えます(プログラムのダウンロード時間などは大きく変わらないと思いますので)
変更前 | 変更後 | 備考 | |
---|---|---|---|
totalの実行時間 | 5.8 秒 | 1.1 秒 | Billed Durationの値 |
Init Duration | 0.5 秒 | 0.8 秒 | 変更後:S3クライアント生成時間が含まれる(+0.3秒) |
S3クライアント生成時間 + S3put時間 |
5.3 秒 | – | |
S3put時間 | (0.3 秒) | 0.3 秒 | |
S3クライアント生成時間 | (5 秒) | (0.3 秒) | 変更前:S3putが0.3秒かかるとした場合(5.3 – 0.3 = 5) 変更後:グローバルスコープに追加したS3クライアント生成処理分 |
変更前の予想では、S3クライアントの生成時間が含まれる5秒程度が、変更後はInit Duration側に移動してtotalの実行時間は変更前同様に6秒程度となるかと思っていました。
実際には、5秒→0.3秒程度と減少しました!
この理由を色々調べると、boost host CPUという仕様の恩恵であるとわかりました!
簡単に言いますと、グローバルスコープの処理について、10秒以内で処理できる範囲なら、高スペックな環境で処理できる、というものです。ですので、lambda_handler内に置くよりも処理時間を短縮できます(各呼び出しで横断的な処理が対象)。
ここの恩恵を受けていたというわけです。
- lambda_handler内部での処理では、設定したスペック(デフォ:メモリ128 MBとそれに応じたvCPU)で処理しないといけない、つまり、貧弱なvCPUでの処理となる
- グローバルスコープの処理は、boost host CPUという仕様により、1769 MBのメモリが割り当たり、このメモリに応じたvCPUが使われ、10秒の範囲で高速に処理できる(参考記事のYouTube動画18分〜)
- LambdaのメモリとCPUの使われ方:割り当てられたメモリに応じた1vCPUが使われる(Lambdaの仕様)
- グローバルスコープで用意したリソースは、各呼び出しで使い回せるだけでなく、その処理自体が高速に処理できるとわかりました
- Lambdaのライフサイクルについて理解が深まりました
- Lambdaのパフォーマンス最適化については、本記事で紹介した以外にもいろんなテクニックがあるので、Lambdaを触る際には都度意識したいと思います
- boost host CPUというネーミングがイケてると思いました
Views: 0