Spring MVC As AWS Lambda
Oleg Zhurakousky氏とMark Sailes氏は、MVC型ワークロードをAWS Lambdaで実現するために「Spring Cloud Function」と「AWS Serverless Java Container」の2つのフレームワークについて紹介しました。
AWS LambdaとJava Springについて
AWS Lambdaはサーバーレスアーキテクチャとして、自動スケーリング、コスト効率、および管理の簡素化といった数多くのメリットを持っています。Spring Cloud Functionを活用することで、Javaの関数をAWS Lambdaに簡単にデプロイできます。さらにServerless Java Containerを利用することでSpring FrameworkのハンドラをLambdaのハンドラとして活用できるため、Spring MVCのコントローラのハンドラをLambda上でそのまま使用することができます。その仕組みとして、Lambdaで発生するイベントをHTTPリクエストに変換していることが説明されました。
Spring BootをLambdaで構築した場合とサーバ有で構築した場合の比較
Lambdaが万能であるというわけではなく、アプリケーションの特定の要件に合わせて、適切なアーキテクチャを選択することが重要であることを強調しました。Spring BootをLambdaで構築した場合とサーバ有で構築した場合のメリットとデメリットは次のように説明されました。
サーバ有で構築した場合
メリット
- 継続的な高トラフィックに対しては、コスト効率が良い
デメリット
- 高トラフィックの際には、処理能力のリミットに達してしまい、リクエストの遅延や失敗が発生する可能性がある
- トラフィックがない場合でも一定のインフラコストがかかる
- スケールアップする仕組みを自分で作成する必要がある
Lambdaで構築した場合
メリット
- 自動スケーリングにより、負荷が急増しても柔軟に対応
- トラフィックがない場合には、料金が発生しない
- スケールアップする仕組みを自分で作成する必要がない
デメリット
- 継続的に高トラフィックが続くシナリオでは、サーバ有での構築に比べてコストが高くなる
Lambdaの仕組みとCold Start高速化の方法について
AWS Lambdaが実行される仕組みと実行速度をどのように高速化するかについても言及されました。Lambdaの初期化には、AWSが最適化する項目(環境の作成、コードのダウンロード、実行環境の起動)と、開発者が最適化する項目(関数の初期化)の2種類があります。Cold Start時に必要なこれらの初期化処理は、Lambdaの実行に時間がかかってしまう原因となっています。Javaを用いた際にCold Startを最適化する仕組みが説明されました。
※動画の約30分以降から音声が切れていますが、過去の発表(「Controller to Zero with AWS Lambda or Azure Functions」と「AWS Lambda Under the Hood」)の内容で参考にできます。
Cold StartとWarm Start
Lambdaの呼び出しには2種類の状態があります:
- Warm Start:過去に作成された実行環境で再利用するため、即座に実行する
- Cold Start:実行環境を新しく作成する処理が必要なため、実行環境を準備する初期化処理で遅延が発生する
Cold Startによる遅延を最小限に抑えるためには、いくつかの改善策があり、デモを通して高速化の仕組みが説明されました。
SnapStartによるCold Startの改善
SnapStartという仕組みにより、Cold Start時の遅延を解消することができます。SnapStartでは、関数の初期化まで済んだ状態のLambdaのVMのスナップショットを保存します。さらにスナップショット全体を多数のチャンクに分割し、必要な部分をキャッシュを利用しながら読み込みます。これにより、Cold Start時の遅延を改善できることが述べられました。
その他のCold Start高速化手段
SnapStart以外にも、Cold Startを高速化する方法があります。例えば、GraalVMを使用してネイティブイメージを作成する手法があります。GraalVMによって作成されたネイティブイメージは、より迅速に起動できるため、Cold Start上でもパフォーマンスが向上することが言及されました。
最後に「将来的に我々はビジネスロジックのみをコーディングすることになる」と「経験で得られる過程を省略する仕組みは存在しない」という内容で締めくくられました。
Let’s Explore Spring Security 6.4
本セッションでは、Spring Securityのプロジェクトリードを務めるRob Winch氏が、主に認可機能に焦点を当てて解説を行いました。特にMethod Securityに注目して、どのようにそれを使うことができるかを、簡単なアプリケーションに対してテストを実装していくデモ形式で解説しています。
目新しい内容は多くありませんが、Spring Securityの最新のベストプラクティスを身につけたい開発者や、認可を伴うテストを行いたい開発者にとって有用なセッションとなるでしょう。
ここでは、このセッションの中で紹介されたトピックをいくつかピックアップしてご紹介します。
Rob Winch氏はこのセッションの冒頭で、Method Securityを利用することで、ドメインロジックと認可のロジックを分離できる点が重要であると述べました。これを示すため、まずはMethod Securityを利用しない場合のコードを示し、その後Method Securityを利用した場合のコードを示すことで、その違いを説明していました。また、説明の過程では、Spring Securityが内部で実現していることについても触れられており、興味のある方はセッションの動画をご覧いただくことをお勧めします。
はじめに示されたのは、サービス用のテストクラスの中に書かれていたログインとクリーンアップ処理の代わりに、@WithMockUserアノテーションを利用したテストの例でした。このアノテーションを利用することで、簡単に認証済みのユーザーをシミュレートしてテストを行うことができます。また、@WithMockUserアノテーションに、あらかじめ必要なパラメータを埋め込んだカスタムアノテーション(ペルソナ)を作ることも紹介されています。このようにすることでテスト上必要なユーザを定義することができ、管理も一箇所で行うことができるため、有用なテクニックと感じました。
次に、サービスクラスのメソッドに対して、@PreAuthorize/@PostAuthorizeアノテーションを利用した認可を行う例が紹介されました。このアノテーションを利用することで、メソッドの実行前後に認可チェックを行うことができます。ここでも、あらかじめ必要なパラメータを埋め込んだカスタムアノテーションを作ることが紹介されており、@WithMockUserの際と同様に、認可の条件を一元的に管理することができ便利だと感じました。
また、認可エラー時の例外ハンドリングについても、MethodAuthorizationDeniedHandlerインターフェースの実装クラスを作り、@HandleAuthorizationDeniedアノテーションでMethodAuthorizationDeniedHandlerの実装クラスを指定することで、ドメインロジックから分離できることや、実際のアプリケーション(例えばRESTアプリケーション)としてテストを行う際の注意点として、Spring Securityを利用していると、ドメインオブジェクトを単純にJSONにシリアライズすることができないため、ドメインオブジェクトに@JsonSerializeアノテーションを付与しておく必要があることなどが紹介されました。
最後に、@PreAuthorize/@PostAuthorizeアノテーションなどで使われるSpEL式で表現される判定式を、SpringのBeanにロジックとして記述する方法についても紹介され、セッションは締めくくられました。