AWS Lambda SnapStart for Java functionsを試してみる(2022/12/18 Update Ver.)
AWS LambdaとServerless Advent Calendar 2022 12/18分の記事です。
re:InventのEXPOにあるAWSのServerless&Containerのコーナーで、全然会話できなくて、I love Lambdaと言って帰ってきたダメな人です。
さて、2022/11/28(現地時間)のMonday Night Liveで登場したLambda SnapStartを早速試してみました。
実は昔はJavaな人だったので(今回コード全く書いてないけど)
Lambda SnapStartとは
Lambda SnapStartについてはこちらをご覧ください。(Now English Only)
Javaのコールドスタートが遅い(ウォームスタートは全ランタイム中最速レベルのはず)問題は、Javaランタイム登場当初からずっとあった話で、その解決となる1つの手段なのではないかと思います。
レイテンシー重視の場合は、Provisioned Concurrencyを利用せよと書かれています。
※Provisioned ConcurrencyではLambda SnapStartは使えないとのこと。
やってみた
とりあえず、アナウンスのJeff Barr氏のブログと同じく、Githubにある「Serverless Spring Boot 2 example」を使ってJavaのアプリをデプロイします。
Java11(Corretto)、SAM CLI、Gradle等が入っていなかったので、この時点で新規インストールします。(現地時間11/29 6時半ぐらい)
設定
とりあえず、設定なしで実行し、問題ないことを確認したら、
ブログ記事にを参考に、SnapStartの設定を行います。
そして、ビルド&デプロイを実行・・・。こけました。
SnapStartってパラメータないよ!?
ここで、SAM CLIのバージョンおよびReleaseを見てみると、11/29のSnapStart対応のSAM CLIが出ており(v1.66.0)、インストールしてあったのは、v1.65.0だったので、絶妙なタイミングで旧バージョンをダウンロードしていたようでした。
ということでSAMのアップデートを実施したところ、このエラーは回避しました。
気を取り直して、最新バージョンのSAM CLIで実行し、SnapStartの設定を行います。
設定後のコンソールはこんな感じになりました。
ちなみに、こちらは設定なしの場合
そして、APIあるので、叩いてLambdaをInvokeしてみます。
1回目。めっちゃ時間かかる・・・。6秒かかってます。
初回は仕方ない(と思っている)ので、ちょっと直して、デプロイして、
再度LambdaをInvokeしてみますが、何度やっても6秒・・・。
これは何か失敗しているなと、
ドキュメントを眺めたり、
セッションがあったので、受講してみたところ、バージョンの作成が必要であることがわかりました。
I rebuilt and redeployed, published a fresh version of the function to set up SnapStart, and ran another test: って書いてありました。OMG!!!
バージョンを作成し、いざInvoke
本来はSAMで頑張るべきところでしょうが、とりあえずコンソール上で、バージョンを指定します。
バージョン作成画面にもSnapStartに関する説明が書いてありました。
そして、作成。
バージョン指定の設定画面では以下のような表示になります。
すると、大量のLogStreamが作成(事実上のコンテナ起動)されました。Provisioned Concurrencyみたいな挙動を感じます。
中身を見てみると、init処理が実行されていました。
そして、テストで設定ありのバージョンのLambdaをInvokeしてみると、実行速い!
ログを見ますと、init処理がなく、RESTORE 〜 という2行が出力されており、217msで起動していることがわかります。6s -> 217msは確かに速い。
という感じで、ハマりましたが、動作の確認までできました。うーん。これはすごい
まとめ
- JavaかつCorretto限定だけど、これは熱いアップデートなのでは?
- これ他のランタイムにもこないかな?
- バージョン指定忘れずに。
- 現状、Graviton2(arm64)では使えない注意。
- 間違えてarm64で実行した人です。
- とはいえ、レイテンシー重視の場合は、Provisioned Concurrencyを利用せよと書かれています。※Provisioned ConcurrencyではLambda SnapStartは使えないとのこと。(再掲)
- 次はAWS CDKでやってみようかな(最近はCDKを多用している人です)
- もう1つ、Monday Night LiveでLambdaのCasheの話が出てきたと思うんだけど、そういえば全然話に出てこない・・・。確かにCacheと書いてあるので、これなのかなぁ・・・。
- このSnapshot Cacheは14日間は残り続けるらしいので、その間はinitなしで実行される
- 15日後にどうなるか試してみたいところ。忘れなかったら追記します。
2022/12/18 Update
15日過ぎたので、どうなっているか、確認してみました。
定期的に、ログが出ているので、コンテナの再作成しているみたいな挙動しています。
15日過ぎ去った2022/12/18、再度テスト実行しよう(その間全く触らずにおりました)と思って、最新バージョンのテストページへ・・・。
え、テスト実行できない???
SnapStart用のCache削除=バージョンの失効?的な挙動なんでしょうか?
ちょっと詳細調べてみたいと思います。
バージョン指定しないで実行すれば、普通に起動に6sかかります。
気を取り直して、ちょっと修正して、再度BuildおよびDeployを実施します。
が、バージョン作成時(厳密にはSnapStart用のCache(コンテナ)起動時)にエラーが出る。
Cloudwatch Logsを見ると、こんな感じのエラーが。
Error loading class com.amazonaws.serverless.sample.springboot2.StreamLambdaHandler: com/amazonaws/serverless/sample/springboot2/StreamLambdaHandler has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0: java.lang.UnsupportedClassVersionError
java.lang.UnsupportedClassVersionError: com/amazonaws/serverless/sample/springboot2/StreamLambdaHandler has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(Unknown Source)
at java.base/java.security.SecureClassLoader.defineClass(Unknown Source)
at java.base/java.net.URLClassLoader.defineClass(Unknown Source)
at java.base/java.net.URLClassLoader$1.run(Unknown Source)
at java.base/java.net.URLClassLoader$1.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.net.URLClassLoader.findClass(Unknown Source)
・・・OSのバージョンアップしたから?
とりあえず、調べたところ、以下のような解決策が載っていたので、
build.gradleに以下を追加し、build&デプロイ後、バージョンの作成を行ったところ、正常に新規バージョンの作成が完了しました。
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}
そして、バージョンのテスト実行画面にいくと、実行できる!
そして、実行すれば、restore処理234.28 msで起動してくれるのでした。
その後、テスト実行できなかったバージョンの画面にいくと、こんな感じの通知が。
なるほど、復元しないとダメなのね?ということで、押してみます。
なんかエラー出た。
Capacity Overらしい。これが一時的なものかがわからないので、別日に実行してみます。年末だから、足りてないかもなぁ・・・。
アップデート内容のまとめ
- 実行後、15日放置するとアイドル状態なり、テスト実行すらできなくなる。
- (おそらく)復元で復活できる(別?のエラーが出たので、これは継続調査)
- 新しいバージョンを発行すれば、無論そのバージョンではSnapStartでCacheできる(当たり前といえば当たり前)
なんか中途半端なアップデートの記載になりましたが、以上です。
Discussion