Lambdaのコールドスタートを解決するLambda SnapStartのセッションに参加してきた(SVS320) #reinvent

re:Invent2022のキーノートにて発表されたLambdaのコールドスタートを改善するLambda SnapStartについてのセッションレポートになります。
2022.12.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

先日のre:Invent2022のキーノートにおいて、Lambdaのコールドスタートを大幅に改善する新機能Lambda SnapStartが発表されました。

すでにAWSの公式ブログや、かずえによるLambda SnapStartの解説ブログも出ていますが、この記事では、その新機能のセッションを聴講する機会があったので、内容をお届けします。

Lambda SnapStartってすごいの?…!!

  ( ゚д゚) ガタッ
  /   ヾ
__L| / ̄ ̄ ̄/_
  \/   /

(セッション内容はだいぶ難しかったです…後述してますが、オンデマンド視聴できるようになったら追記予定)

セッション情報

セッション概要

[NEW LAUNCH!] AWS Lambda SnapStart: Fast cold starts for your Java functions SVS320

In this session, learn about the newly released AWS Lambda SnapStart service. With new innovations, AWS SnapStart makes your Java-based function cold starts up to 10x faster, typically with no changes to your function code.

本セッションでは、新しくリリースされたAWS Lambda SnapStartサービスについて学びます。新しいイノベーションにより、AWS SnapStartはJavaベースのFunctionのコールドスタートを最大10倍高速化します。通常、Functionのコードに変更を加えることなく利用することができます。

セッションスピーカー

Mark Sailes, Specialist Solutions Architect, Serverless, AWS

セッション内容

皆さん、こんにちは。来てくださって本当にありがとうございます。こんなにたくさんの方にお会いできるなんて、なんだか圧倒されますね。

私の専門は、API Gateway, Lambda, SNS, SQSなどです。また、私は本当に長い間、Javaプログラミングを学生時代から今まで楽しんできました。普段は、AWS LambdaでJavaアプリケーションをホストしようとしているお客様と一緒に仕事をしています。もしあなたがLambdaでJava Runtimeを使ったことがあるのであれば、これはそんなあなたのためのセッションです。今回リリースされた、SnapStartは本当にクールで最高でファンタスティックです。

ここ数年、Javaの人気が再燃しているように感じます。その理由のひとつは、ここ数年でJavaに導入されたリリース・ケイデンス・チームにあると思います。リリースとリリースの間に長い期間があったのが、今では毎年2回リリースされるようになりました。Javaに新しいイノベーションの波が押し寄せています。

しかし、JavaでLambdaを動作させる時、このようなコールドスタートに苦労した人は多くいるのではないでしょうか。

これは、話をわかりやすくするため誇張した表現にしていますが、傾向としては正しいものです。大多数のリクエストはとても速く動作していますが、少数のリクエストは遅くなります。顧客向けにAPIを実装したり、応答性の高いインタラクションなアプリケーションが必要な場合、これは本当にイライラしますね。わかります!

そこで、SnapStartの新機能を実証するために、非常にシンプルなSpring Bootアプリケーションを作成しました。API Gatewayからリクエストを受け取り、Sprint Boot Functionを起動します。そして、DynamoDBに情報を保存し、取得します。

多くのSpring Bootアプリケーションのコントローラと同じように、このサンプルは多くのMVCアクションを備えています。サービスにはいくつかのビジネスオブジェクトがあります。そして、MongoDBという別のクラスを持っています。ほとんどの場合、起動は非常に速く、30ミリ秒前後で終わります。でもたまに、非常にレスポンスが遅くなる場合があります。この例では6.5秒かかっています。これがコールドスタートです。

こういったコールドスタートをできるだけ減らし、応答性の高いアプリケーションを実現したいものです。

一旦、ここで、なぜこのようなコールドスタートがおこるのか、その理由を把握しておきましょう。Javaにはどのような特徴があるのでしょうか。

Lambdaの実行環境を作るとき、Firecrackerのインスタンスを作り、そのコードをダウンロードしてJavaランタイムを再起動させています。もしあなたがDIを使用するフレームワークを使っているなら、それはかなり多くのリフレクションを実行するため時間がかかります。また、Javaはバイトコードを受け取ったのち、マシン上で動作するようにコンパイルしています。これは実行環境を作るときに起こります。

この問題に対処するため、様々なアプローチが必要となっていました。こちらのスライドに現在のアプローチを記載しています。

基本的なアプローチは全てを、あらかじめ完了させておくことです。Javaコードのコンパイルを先行して実施し、ネイティブな実行ファイルを生成します。最適化は、コールドスタートを改善するための努力にほかなりません。

この領域でイノベーションを起こすことで、お客様のお役に立てるのだと思います。どのようにすればより高速なコード実行環境の作成ができるでしょうか。

私たちは、お客様が簡単に高いスケーラビリティと応答性を構築できるようにしたいと思います。そこで、Lambda SnapStartの登場です。

動作原理を見ていきましょう。

Functionをプロビジョニングすると、コードを初期化し、仮想マシン全体のスナップショットを取得します。そのスナップショットの中にFunctionがあり、そのスナップショットをロードして、低レイテンシーで検索できるようにします。このプロセスの実行中、Functionは保留状態になっています。この状態では、Funcitonの実行はできません。一度起動されるとアクティブな状態に遷移し実行できるようになります。リクエストが来た時、スナップショットから実行環境を復元し、それを利用します。

そのために、バージョンまたはそのバージョンのエイリアスを有効にしていることを指定する必要があります。それらのいずれかを指定しない場合は、SnapStart機能を呼び出すことはできません。ない場合、通常のFunctionを呼び出します。もし初めてこの機能を試してみて、何の変化も見られなかった場合は、この点を確認してください。

では、実際にどのように実現するのかを説明します。

スナップショット処理の前後にコードを実行する機会があります。これはJavaで書かれたハンドラの例です。そして、ここにインターフェースを追加しました。これはオープンJDKで利用可能なインターフェイスで、CRaCというプロジェクトの一部です。少なくとも、OpenJDKプロジェクトは外部依存です。

その結果、2つのメソッドが追加されていることがわかります。これはすべてのハンドラに追加する方法です。そして、いくつかのメッセージを出力しています。

ではなぜステップの前後にコードを走らせたいのでしょうか?それは、考慮すべき事柄のいくつかをお伝えしたいからです。

Network connections

ラムダ関数のタイムアウトがデータベースの中で発生する可能性があります。理由はいくつもあり得ます。

Ephemeral data

この例では、機密情報について説明します。DB接続パスワード、あるいは同様のアプリケーションの固有設定を作成するかもしれません。これらは秘密にしておきたいのですが、もし機密情報がスナップショットから取得できるような場合も有りえます。ので、エラーになったり、無限に不正な認証情報を取得される可能性があることを気をつけておく必要があります。

Uniqueness

私たちはスナップショットから新しい実行環境を作っています。これが問題を起こすことはよくありえます。例えば、乱数を生成するとき同じシードを持ちたくはありません。

AWSはAmazon LinuxをオープンSSLに更新して、スナップショット処理に弾力性を持たせるようにしました。乱数を生成するためにホストのベストプラクティスを使用している場合、これはそれを行うための方法です。

具体的には、こちらで紹介している、java.security.SecureRandomの利用を検討してください。

以下が、上記の結果になります。

平均的なレスポンスタイムは全て8ミリ秒です。これは全ての結果で同じです。SnapStartがない場合、p99.9において、5000ミリ秒を超えていて、これは非常に長いコールドスタートが発生していることを表しています。

SnapStartを利用することで、p99.9の値でも500ミリ秒を維持しており、ほぼすべてのケースにおいて、コールドスタートを回避できていることが示されています。

Java利用において活用してもらいたいツール郡

普段Javaを利用していて、Lambdaに興味をお持ちの方は、是非こちらのツールを活用してみてください。

また、実際に手を動かして学ぶためのワークショップも用意しています。

最後に

私たちは、コンテナには決してフォーカスしていません。私たちは、Lambdaのためのベストプラクティスを作っているだけなのです。私たちはコミュニティの声に耳を傾けてきました。これからのLambdaの進化にも注目いただけると幸いです。ご静聴ありがとうございます!

セッションを聞いた所感

以上、セッション会場で聞いた内容を手元メモと画像を参考に起こしてみました。

Javaの起動方式の説明から、SnapStartがどう動いて何を解決しようとしているのかを丁寧に説明してもらい理解が深まりました。ただ、セッションを聞いていて正直理解ができていない部分や、聞きそこねた部分、特に最後にJavaの内部構造についての話があったのですが、私の実力不足でその部分を大きく省略しています。

恐らく、このセッションも追ってオンデマンドで視聴できるようになると思うので、そのときは不足部分を追記させていただきます。

それでは、今日はこのへんで。濱田(@hamako9999)でした。

Lambda SnapStart関連情報

以下、Lambda SnapStartについての、公式ブログです。以下も合わせて参考にしてもらえれば理解が深まるかと思います!

AWSの公式ブログ。

AWSの公式ドキュメント。

かずえさんが書いた、アップデートブログ。