SpringBootでLambda SnapStartを試してみた
TL;DR
- SnapStartを使うとLambdaがコールドスタートの場合の起動時間を短縮できる
- LambdaでSpringBootを抱えた場合でもコールドスタートで1000ms以内に返せる(かも)
経緯
SpringBootをサーバーレスで実行するには、ECS+Fargateのようなコンテナ構成をよく利用している。 (ECSでサービス+ELBを立てて、warm状態でスタンバイしておき、requestを待ち受ける構成)
この場合、fargateが時間課金であるためにリクエストがない場合でも待機コストがかかる。
これをLambdaにすることでpay as you goスタイルにできるのだが、 Lambdaの場合はリクエストがないと一定時間経過後にtimeoutし、次のリクエストまではコールドスタートとなり レイテンシーが上がってしまう。
特にJavaは起動時のレイテンシーが高く、これがネックで採用を見送っていた。 (Lambdaのprovisionedを使えばレイテンシーは解決できるが、時間課金になってしまう)
これが re:Invent 2022で発表されたLambda SnapStartにより短縮できるとのことなのでやってみた
手順
サンプルリポジトリ を作った。
ベースは aws公式のリポジトリ
VSCodeのdevcontainerで開き、samを使ってデプロイできるようにしてある
環境
- Java21
- SpringBoot3
- Gradle8.5
- AWS sam 1.113.0
SnapStart制限
- 2024/3時点でSnapStartはjava11以降、かつjavaのmanaged runtimeのみサポート
- arm64は未サポート
- EFS未サポート
- storageは512MBまで
SnapStartを有効にするには
以下を満たすことでSnapStartが自動的に配備される ソースコード上の依存ライブラリ追加は不要
- Lambdaの設定で SnapStartの項目に
PublishedVersions
を設定 - Lambdaの新しいversionを発行する
samを使う場合、 template.yml
に以下の記述を追加することで対応できる
1Resources:
2 SnapStartDemoFunction:
3 Type: AWS::Serverless::Function
4 Properties:
5 Handler: com.amazonaws.serverless.sample.springboot3.StreamLambdaHandler::handleRequest
6 Runtime: java21
7 CodeUri: .
8 MemorySize: 128
9 Policies: AWSLambdaBasicExecutionRole
10 Timeout: 60
11 # ここと
12 SnapStart:
13 ApplyOn: PublishedVersions
14 # ここ
15 AutoPublishAlias: live
16 Events:
17 HttpApiEvent:
18 Type: HttpApi
19 Properties:
20 Path: /{proxy+}
21 Method: any
22 TimeoutInMillis: 20000
23 PayloadFormatVersion: '1.0'
ソースコードでの対応
公式サンプル
にあるようにAPI Gateway配下でSpringBootを動かすのに SpringBootLambdaContainerHandler
が便利なので利用する。
これを使うことでrequestとresponseをLambdaのプロキシ統合に自動的に合わせてくれる。 (spring側は通常どおりrequest/responseを操作できる)
また、公式docのPerformance tuning にある通り、SnapStartのより効かせるために、対象APIのダミーリクエストを初期化コードとして埋め込んだ。
これによりSnapShotの中でAPIで必要なclassも読み込まれている状態でrestoreされるので、より起動が早くなるらしい。
実行結果
- SnapStartなし、coldスタート:
973ms
〜1028ms
- SnapStartあり、coldスタート、preloadの加工あり:
515ms
〜633ms
これだけだと言うほどあまり早くなっていないが、preloadされるclassが多くなればなるほどSnapStartの効果が効いてくるものと思われる。
その他
SnapStartでresoreされた状態はDBコネクション等は当然接続しなおしが必要となる。 その他、hostname、ポート、DNSキャッシュあたりの振る舞いについては確認が必要
また、SnapStartとは直接関係ないがLambdaでSpringを抱えるうえでパフォーマンス改善につながる要素は対応を検討