AWS Lambdaを使用したサーバーレスコンピューティング、パート1

サーバーレスコンピューティングは、今日のクラウドコンピューティングで最も注目されているものかもしれませんが、正確には何ですか?この2部構成のチュートリアルは、サーバーレスコンピューティングの概要から始まります。サーバーレスコンピューティングとは何か、従来のクラウドコンピューティングを混乱させると考えられる理由、Javaベースのプログラミングでの使用方法などです。

概要に続いて、AWS Lambdaの実践的な紹介を行います。これは、今日のサーバーレスコンピューティング向けの多くのプレミアJavaベースのソリューションで検討されています。パート1では、AWS Lambdaを使用して、Javaで最初のLambda関数をビルド、デプロイ、テストします。パート2では、Lambda関数をDynamoDBと統合してから、AWSSDKを使用してJavaアプリケーションでLambda関数を呼び出します。

サーバーレスコンピューティングとは何ですか?

昨年、私はさまざまなアーキテクチャパターンについて会社のインターンと話し、サーバーレスアーキテクチャについて言及しました。彼は、すべてのアプリケーションがサーバーを必要とし、薄い空気では実行​​できないことにすぐに気づきました。たとえ彼が私の行方不明であったとしても、インターンはポイントを持っていました。サーバーレスコンピューティングは、アプリケーションを実行するための魔法のプラットフォームではありません。

実際、サーバーレスコンピューティングとは、開発者であるあなたがサーバーを扱う必要がないことを意味します。AWS Lambdaのようなサーバーレスコンピューティングプラットフォームを使用すると、基盤となるサーバーを構成または管理することなく、コードをビルドしてデプロイできます。デプロイメントの単位はコードです。コードをホストするコンテナやコードを実行するサーバーではなく、単にコード自体です。生産性の観点から、コードが格納されている場所と実行環境の管理方法の詳細をオフロードすることには明らかな利点があります。サーバーレスコンピューティングも実行メトリックに基づいて価格設定されるため、経済的な利点もあります。

AWS Lambdaの費用はいくらですか?

この記事の執筆時点では、AWS Lambdaの価格階層は、実行回数と実行期間に基づいています。

  • 1か月あたりの最初の100万回の実行は無料で、その後は100万回の実行あたり$ 0.20を支払います(リクエストあたり$ 0.0000002)。
  • 期間は、コードの実行が開始されてから結果が返されるまで計算され、100ミリ秒単位で四捨五入されます。請求される金額は、関数に割り当てられたRAMの容量に基づいており、コストはGB秒ごとに$ 0.00001667です。

価格の詳細と無料利用枠の割り当ては、概要が示すよりも少し複雑です。価格階層にアクセスして、いくつかの価格シナリオを確認してください。

サーバーレスコンピューティングがどのように機能するかを理解するために、図1に示すサーバーレスコンピューティングの実行モデルから始めましょう。

スティーブンヘインズ

簡単に言うと、サーバーレス実行モデルは次のとおりです。

  1. クライアントは、サーバーレスコンピューティングプラットフォームに特定の機能を実行するように要求します。
  2. サーバーレスコンピューティングプラットフォームは、最初に、関数がそのサーバーのいずれかで実行されているかどうかを確認します。関数がまだ実行されていない場合、プラットフォームはデータストアから関数をロードします。
  3. 次に、プラットフォームは、関数を実行できる実行環境で事前構成されたサーバーの1つに関数をデプロイします。
  4. 関数を実行し、結果をキャプチャします。
  5. 結果をクライアントに返します。

サーバーレスコンピューティングは、作成するコードの粒度が関数であるため、Function as a Service(FaaS)と呼ばれることもあります。プラットフォームは独自のサーバーで関数を実行し、関数要求と関数応答の間のプロセスを調整します。

ナノサービス、スケーラビリティ、および価格

サーバーレスコンピューティングでは、3つのことが本当に重要です。そのナノサービスアーキテクチャ。それが事実上無限にスケーラブルであるという事実。そして、ほぼ無限のスケーラビリティに関連する価格設定モデル。これらの各要素について詳しく説明します。

ナノサービス

マイクロサービスについて聞いたことがあるでしょうし、おそらく12ファクターのアプリケーションについて知っているでしょうが、サーバーレス関数は、コンポーネントをその構成要素に分解するというパラダイムをまったく新しいレベルに引き上げます。 「ナノサービス」という用語は業界で認められた用語ではありませんが、考え方は単純です。各ナノサービスは単一のアクションまたは責任を実装する必要があります。たとえば、ウィジェットを作成したい場合、作成の行為はそれ自体のナノサービスになります。ウィジェットを取得したい場合、取得の動作もナノサービスになります。ウィジェットを注文したい場合、その注文はさらに別のナノサービスになります。

ナノサービスアーキテクチャを使用すると、アプリケーションを非常にきめ細かいレベルで定義できます。テスト駆動開発(個々のテストのレベルでコードを記述することで不要な副作用を回避するのに役立ちます)と同様に、nanoservicesアーキテクチャは、非常にきめ細かい特定の機能の観点からアプリケーションを定義することを推奨します。このアプローチにより、構築しているものが明確になり、新しいコードによる不要な副作用が軽減されます。

マイクロサービスとナノサービス

マイクロサービスは、アプリケーションを、それぞれが特定のタスクを実行するサービスのコレクションに分割することをお勧めします。課題は、マイクロサービスの範囲を実際に定量化した人がいないことです。その結果、マイクロサービスを関連サービスのコレクションとして定義し、すべてが同じデータモデルと相互作用することになります。概念的には、特定のデータモデルと相互作用する低レベルの機能がある場合、その機能は関連するサービスの1つに組み込まれる必要があります。高レベルの対話では、データベースに直接クエリを実行するのではなく、サービスを呼び出す必要があります。

サーバーレスコンピューティングでは、マイクロサービスとナノサービスのどちらのレベルでLambda関数を構築するかについて議論が続いています。幸いなことに、どちらの粒度でも関数を非常に簡単に構築できますが、マイクロサービス戦略では、リクエストハンドラーに少し追加のルーティングロジックが必要になります。

設計の観点から、サーバーレスアプリケーションは非常に明確でクリーンである必要があります。デプロイメントの観点からは、かなり多くのデプロイメントを管理する必要がありますが、他の関数に影響を与えることなく、関数の新しいバージョンを個別にデプロイすることもできます。サーバーレスコンピューティングは、大規模なチームでの開発に特に適しています。サーバーレスコンピューティングは、開発プロセスを容易にし、コードでエラーが発生しにくくするのに役立ちます。

スケーラビリティ

サーバーレスコンピューティングプラットフォームは、新しいアーキテクチャパラダイムの導入に加えて、実質的に無限のスケーラビリティを提供します。本当にそんなことはないので「実用的に」と言います無限のスケーラビリティ。ただし、すべての実用的な目的で、Amazonのようなサーバーレスコンピューティングプロバイダーは、あなたがそれらに投げかけることができるよりも多くの負荷を処理することができます。需要の増加に対応するために独自のサーバー(またはクラウドベースの仮想マシン)のスケールアップを管理する場合は、使用状況を監視し、サーバーを起動するタイミングを特定し、適切なタイミングでサーバーをクラスターに追加する必要があります。同様に、需要が減少した場合は、手動でスケールダウンする必要があります。サーバーレスコンピューティングでは、サーバーレスコンピューティングプラットフォームに、実行する同時関数リクエストの最大数を指定すると、プラットフォームがスケーリングを実行します。

価格設定

Finally, the serverless computing pricing model allows you to scale your cloud bill based on usage. When you have light usage, your bill will be low (or nil if you stay in the free range). Of course, your bill will increase with usage, but hopefully you will also have new revenue to support your higher cloud bill. For contrast, if you were to manage your own servers, you would have to pay a base cost to run the minimum number of servers required. As usage increased, you would scale up in increments of entire servers, rather than increments of individual function calls. The serverless computing pricing model is directly proportional to your usage.

AWS Lambda for serverless computing

AWS Lambdaは、EC2やS3などのAmazon WebServicesプラットフォーム上に実装されたサーバーレスコンピューティングプラットフォームです。AWS Lambdaは、コードを暗号化してS3に保存します。関数の実行が要求されると、ランタイム仕様を使用して「コンテナー」が作成され、コンピューティングファーム内のEC2インスタンスの1つにデプロイされ、その関数が実行されます。このプロセスを図2に示します。

スティーブンヘインズ

When you create a Lambda function, you configure it in AWS Lambda, specifying things like the runtime environment (we'll use Java 8 for this article), how much memory to allocate to it, identity and access management roles, and the method to execute. AWS Lambda uses your configuration to setup a container and deploy the container to an EC2 instance. It then executes the method that you've specified, in the order of package, class, and method.

At the time of this writing, you can build Lambda functions in Node, Java, Python, and most recently, C#. For the purposes of this article we will use Java.

What is a Lambda function?

When you write code designed to run in AWS Lambda, you are writing functions. The term functions comes from functional programming, which originated in lambda calculus. The basic idea is to compose an application as a collection of functions, which are methods that accept arguments, compute a result, and have no unwanted side-effects. Functional programming takes a mathematical approach to writing code that can be proven to be correct. While it's good to keep functional programming in mind when you are writing code for AWS Lambda, all you really need to understand is that the function is a single-method entry-point that accepts an input object and returns an output object.

Serverless execution modes

While Lambda functions can run synchronously, as described above, they can also run asynchronously and in response to events. For example, you could configure a Lambda to run whenever a file was uploaded to an S3 bucket. This configuration is sometimes used for image or video processing: when a new image is uploaded to an S3 bucket, a Lambda function is invoked with a reference to the image to process it.

I worked with a very large company that leveraged this solution for photographers covering a marathon. The photographers were on the course taking photographs. Once their memory cards were full, they loaded the images onto a laptop and uploaded the files to S3. As images were uploaded, Lambda functions were executed to resize, watermark, and add a reference for each image to its runner in the database.

All of this would take a lot of work to accomplish manually, but in this case the work not only processed faster because of AWS Lambda's horizontal scalability, but also seamlessly scaled up and back down, thus optimizing the company's cloud bill.

In addition to responding to files uploaded to S3, lambdas can be triggered by other sources, such as records being inserted into a DynamoDB database and analytic information streaming from Amazon Kinesis. We'll look at an example featuring DynamoDB in Part 2.

AWS Lambda functions in Java

Now that you know a little bit about serverless computing and AWS Lambda, I'lll walk you through building an AWS Lambda function in Java. 

ダウンロードこのチュートリアル「AWSLambdaを使用したサーバーレスコンピューティング」のサンプルアプリケーションのコードソースコードを入手してください。JavaWorldのためにStevenHainesによって作成されました。

Lambda関数の実装

Lambda関数は、次の2つの方法のいずれかで記述できます。

  • この関数は、クライアントへの入力ストリームを受信し、クライアントに出力ストリームに書き込むことができます。
  • 関数は事前定義されたインターフェースを使用できます。その場合、AWS Lambdaは入力ストリームをオブジェクトに自動的に逆シリアル化し、関数に渡し、関数の応答をシリアル化してからクライアントに返します。

AWS Lambda関数を実装する最も簡単な方法は、事前定義されたインターフェースを使用することです。Javaの場合、最初に次のAWS Lambdaコアライブラリをプロジェクトに含める必要があります(この例ではMavenを使用していることに注意してください)。

 com.amazonaws aws-lambda-java-core 1.1.0  

Next, have your class implement the following interface:

Listing 1. RequestHandler.java

 public interface RequestHandler { /** * Handles a Lambda function request * @param input The Lambda function input * @param context The Lambda execution environment context object. * @return The Lambda function output */ public O handleRequest(I input, Context context); } 

The RequestHandler interface defines a single method: handleRequest(), which is passed an input object and a Context object, and returns an output object. For example, if you were to define a Request class and a Response class, you could implement your lambda as follows:

 public class MyHandler implements RequestHandler { public Response handleRequest(Request request, Context context) { ... } } 

Alternatively, if you wanted to bypass the predefined interface, you could manually handle the InputStream and OutputStream yourself, by implementing a method with the following signature:

 public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { ... } 

The Context object provides information about your function and the environment in which it is running, such as the function name, its memory limit, its logger, and the amount of time remaining, in milliseconds, that the function has to complete before AWS Lambda kills it.