Lambdaのコールドスタート“最初の10秒”の輝き ─ boost host CPUの恩恵を体感した話

AWS Lambdaには、コールドスタート時に **最大10秒間だけCPUとメモリリソースが強化される「boost host CPU」** という仕様があるのをご存知でしょうか？

Lambdaのリファクタとして、各呼び出しで共通するリソース用意の処理(S3クライアントを生成するコード)をグローバルスコープに移動したところ、なぜか処理時間が短縮されました。
「S3クライアントの初期化のタイミングが変わっただけで、全体の実行時間は変わらないだろう」と思っていたのですが、処理時間が短縮した事実から、調べるとboost host CPUという仕様の恩恵を受けていたことがわかりました。

本記事では、変更前後の処理時間の変化、boost host CPUの仕組みについて紹介します。




# 前提
Lambda初心者向けの記事ですので、必要に応じて以下のトグルを展開してください。
<details><summary>用語の説明や環境</summary>


- 「S3クライアント」の意味
    - AWS S3の操作をするためのオブジェクト
    - クライアントタイプのAPI、リソースタイプのAPIは本記事では区別せずとします
- Lambdaのコールドスタートとグローバルスコープ
    - コールドスタートとは、Lambdaがリクエストを処理する際に、まだ準備ができていない状態（インスタンスが存在しない状態）から新しい実行環境（コンテナ）を起動して関数コードを読み込む処理のことです
    - 初回実行時や、しばらく使われていなかったときにコールドスタートとなり、この時、関数の初期化(ダウンロード)やグローバルスコープの処理が実行されます
    - グローバルスコープとは、Lambda関数ファイル内で lambda_handler（エントリーポイント）の外側に書かれたコード領域を指します
    - 詳細は[公式](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtime-environment.html)をご参照ください
- Lambdaの環境
    - コンテナLambdaにてRuby 3.2を指定（コンテナイメージで指定）
    - メモリ：128 MB(デフォルト)
    - エフェメラルストレージ：512 MB(デフォルト)
</details>


# やったこと
- 受け取ったイベントをS3のオブジェクトとしてputするだけの処理をするLambdaに対して以下の変更を行いました
- [ベストプラクティス](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/best-practices.html#function-code)に沿って、S3クライアントの生成処理をlambda_handler内ではなくグローバルスコープ側に移動しました
![SCR-20250525-oigd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916574/bd96a2b9-2a3f-4518-ad00-96ce85f8849c.png)


# 効果観測
CloudWatchメトリクスとログで効果を観測しました。<br>
▼メトリクス
![スクリーンショット 2025-05-25 16.10.32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916574/308f9280-0014-4647-b66f-505342f658de.jpeg)



深夜から明朝の時間帯で、"点"だけのところが比較しやすいと思います(上図赤枠)。
この点はDuration averageとmaximumが同値となる点、つまり1回だけの呼び出しの記録点であることを意味し、初期化を伴う呼び出しとなったことを表す点です（CloudWatchログでも確認済み）。
Duration maximum、この場合はつまり初期化を伴う実行時間が、4−5秒減少したことがわかりました！

<details><summary>CloudWatchログの結果</summary>

▼変更前
![SCR-20250525-olaz.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916574/62b90776-86b5-4522-8875-683ad9be502e.png)



▼変更後
![SCR-20250525-omya.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916574/1f5d38a3-be63-44bb-97a5-032b842fa0a1.png)

</details>

CloudWatchログから拾った結果を下表の通りまとめました。
- ()内は実測値が普遍的であると仮定した場合の想定値です（正確な実測は端折りました<(_ _;)>）
- なお、Init Durationの値は、解釈を簡単にするため、グローバルスコープの処理時間であると考えます（プログラムのダウンロード時間などは大きく変わらないと思いますので）

|  | 変更前 | 変更後 |備考|
|:-|:-:|:-:|:-|
| totalの実行時間  |5.8 秒|1.1 秒|Billed Durationの値|
| Init Duration |0.5 秒|0.8 秒|変更後：S3クライアント生成時間が含まれる(+0.3秒)|
|S3クライアント生成時間 <br> + S3put時間|5.3 秒|-||
|S3put時間|(0.3 秒)|0.3 秒||
|S3クライアント生成時間|(5 秒)|(0.3 秒)|変更前：S3putが0.3秒かかるとした場合(5.3 - 0.3 = 5)<br>変更後：グローバルスコープに追加したS3クライアント生成処理分|


変更前の予想では、S3クライアントの生成時間が含まれる5秒程度が、変更後はInit Duration側に移動してtotalの実行時間は変更前同様に6秒程度となるかと思っていました。
実際には、5秒→0.3秒程度と減少しました！
この理由を色々調べると、boost host CPUという仕様の恩恵であるとわかりました！

# 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というネーミングがイケてると思いました

# 参考記事🙇🏻
- https://dev.classmethod.jp/articles/lambda-boost-host-cpu-in-init-phase/?utm_source=chatgpt.com
- https://qiita.com/yasuaki9973/items/639336a009f04f77be12?utm_source=chatgpt.com
- https://www.youtube.com/watch?v=zKa-4R2-aDE