

# Lambda アプリケーションの設計
<a name="concepts-application-design"></a>

優れた設計のイベント駆動型アプリケーションは、AWS サービスとカスタムコードを組み合わせてリクエストとデータを処理および管理します。この章では、アプリケーション設計における Lambda 固有のトピックに焦点を当てます。サーバーレスアーキテクトは、ビジーな本番稼働システム向けにアプリケーションを設計する際に、多くの重要な考慮事項があります。

ソフトウェア開発と分散システムに適用されるベストプラクティスの多くは、サーバーレスアプリケーション開発にも適用されます。全体的な目標は、以下を備えたワークロードを開発することです。
+  **信頼性** - エンドユーザーに高い可用性のレベルを実現します。AWS サーバーレスサービスは障害にも備えて設計されているため、信頼性があります。
+  **耐久性** - ワークロードの耐久性のニーズを満たすストレージオプションを用意しています。
+  **安全性** - ワークロードへのアクセスを保護して影響範囲を制限するため、ベストプラクティスに従って提供されるツールを使用します。
+  **パフォーマンス** - コンピューティングリソースを効率的に使用し、エンドユーザーのパフォーマンスニーズを満たします。
+  **コスト効率** - 過剰に支出しなくても増加する可能性がある不要なコストを回避し、大きなオーバーヘッドなしで廃止できるアーキテクチャを設計します。

次の設計原則により、これらの目標を達成するためのワークロードを構築できます。すべての原則がすべてのアーキテクチャに適用されるわけではありませんが、一般的なアーキテクチャの決定の参考になります。

**Topics**
+ [

## カスタムコードの代わりのサービスの使用
](#services-custom-code)
+ [

## Lambda 抽象化レベルの概要
](#level-abstraction)
+ [

## 関数にステートレスの実装
](#statelessness-functions)
+ [

## 結合を最小限に抑制
](#minimize-coupling)
+ [

## バッチではなく、オンデマンドデータ向けに構築
](#on-demand-batches)
+ [

## 複雑なワークフローのオーケストレーションオプションを選択する
](#orchestration)
+ [

## べき等性の実装
](#retries-failures)
+ [

## 複数の AWS アカウントを使用してクォータを管理する
](#multiple-accounts)

## カスタムコードの代わりのサービスの使用
<a name="services-custom-code"></a>

サーバーレスアプリケーションは、通常、Lambda 関数で実行されるカスタムコードと統合された複数の AWS サービスで構成されます。Lambda はほとんどの AWS サービスと統合できますが、サーバーレスアプリケーションで最もよく使用されるサービスは次のとおりです。


| Category | AWS のサービス | 
| --- | --- | 
|  コンピューティング  |  AWS Lambda  | 
|  データストレージ  |  Amazon S3 Amazon DynamoDB Amazon RDS  | 
|  API  |  Amazon API Gateway  | 
|  アプリケーション統合  |  Amazon EventBridge Amazon SNS Amazon SQS  | 
|  オーケストレーション  |  Lambda の耐久性のある関数 AWS Step Functions  | 
|  データのストリーミングと分析  |  Amazon Data Firehose  | 

**注記**  
多くのサーバーレスサービスは、DynamoDB や Amazon S3 など、複数のリージョンのレプリケーションとサポートを提供します。Lambda 関数はデプロイパイプラインの一部として複数のリージョンにデプロイでき、API Gateway はこの設定をサポートするように設定できます。これを実現する方法を示す「[アーキテクチャの例](https://d1.awsstatic.com/architecture-diagrams/ArchitectureDiagrams/serverless-architecture-for-global-applications-ra.pdf?did=wp_card&trk=wp_card)」を参照してください。

分散アーキテクチャには、自分で構築したり、AWS サービスを使用して実装したりできる、確立された一般的なパターンが多数あります。ほとんどのお客様にとって、これらのパターンをゼロから開発するために時間を費やすことによる商業的な価値はほとんどありません。アプリケーションがこれらのパターンのいずれかを必要とする場合は、対応する AWS サービスを使用します。


| パターン | AWS のサービス | 
| --- | --- | 
|  [キュー]  |  Amazon SQS  | 
|  イベントバス  |  Amazon EventBridge  | 
|  パブリッシュ/サブスクライブ (ファンアウト)  |  Amazon SNS  | 
|  オーケストレーション  |  Lambda の耐久性のある関数 AWS Step Functions  | 
|  API  |  Amazon API Gateway  | 
|  イベントストリーム  |  Amazon Kinesis  | 

これらのサービスは Lambda と統合するように設計されており、Infrastructure as Code (IaC) を使用してサービス内のリソースを作成および破棄できます。アプリケーションをインストールしたり、サーバーを設定したりすることなく、[AWS SDK](https://aws.amazon.com/tools/) 経由でこれらのサービスを使用できます。Lambda 関数でコードを介してこれらのサービスを使用することに習熟することは、適切に設計されたサーバーレスアプリケーションを作成するための重要なステップです。

## Lambda 抽象化レベルの概要
<a name="level-abstraction"></a>

Lambda サービスは、Lambda 関数を実行する基盤となるオペレーティングシステム、ハイパーバイザー、ハードウェアへのアクセスを制限しています。このサービスは、インフラストラクチャを継続的に改善および変更して機能を追加し、コストを削減し、サービスのパフォーマンスを向上させています。コードでは、Lambda がどのように設計されているかについての知識がなく、ハードウェアのアフィニティがないことを前提とする必要があります。

同様に、Lambda と他のサービスとの統合は AWS によって管理され、少数の設定オプションのみが公開されます。例えば、API Gateway および Lambda が対話すると、負荷分散はサービスによって完全に管理されるため、負荷分散の概念はありません。いつでも関数を呼び出すときにサービスが使用する[アベイラビリティーゾーン](https://aws.amazon.com/about-aws/global-infrastructure/regions_az/)、あるいは Lambda が実行環境をスケールアップまたはスケールダウンする時期を決定する方法について、ユーザーは直接制御することもできません。

この抽象化により、アプリケーションの統合の側面、データのフロー、ワークロードがエンドユーザーに価値を提供するビジネスロジックに集中できるようになります。サービスが基盤となるメカニズムを管理できるようにすることで、お客様が維持するカスタムコードが減り、アプリケーションをより迅速に開発できます。

## 関数にステートレスの実装
<a name="statelessness-functions"></a>

標準の Lambda 関数には、環境は単一の呼び出しのみに対して存在する考える必要があります。関数を最初に起動するとき、必要な状態を初期化する必要があります。例えば、関数が DynamoDB テーブルからデータ取得が必要な場合があります。終了する前に、Amazon S3、DynamoDB、Amazon SQS などの耐久性の高い保存場所に永続的なデータ変更をコミットする必要があります。既存のデータ構造や一時ファイル、あるいは複数の呼び出しによって管理される内部状態に依存してはなりません。

耐久性のある関数を使用すると、状態は呼び出し間に自動的に保持されるため、状態を外部ストレージに手動で保持する必要がなくなります。ただし、DurableContext で明示的に管理されていないデータについては、ステートレスの原則に引き続き従う必要があります。

データベース接続およびライブラリ、あるいはロード状態を初期化するには、[静的初期化](lambda-runtime-environment.md#static-initialization)を活用できます。パフォーマンスを向上させるために実行環境は可能な限り再利用されるため、これらのリソースを初期化するためにかかる時間は複数の呼び出しに分散できます。ただし、関数で使用される変数やデータは、このグローバルスコープ内に保存しないでください。

## 結合を最小限に抑制
<a name="minimize-coupling"></a>

ほとんどのアーキテクチャでは、より少なく、より長い関数よりも、より多く、より短い関数を優先する必要があります。各関数の目的は、ワークフロー全体やトランザクションの量を把握したり期待したりすることなく、関数に渡されたイベントを処理することである必要があります。これにより、関数は他のサービスとの結合が最小限になり、イベントのソースに依存しなくなります。

頻繁に変更されないグローバルスコープ定数は、デプロイなしで更新できるように環境変数として実装する必要があります。シークレットまたは機密情報は、[AWS Systems Manager パラメータストア](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html)または [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) に保存し、関数によってロードする必要があります。これらのリソースはアカウント固有であるため、複数のアカウントにまたがるビルドパイプラインを作成できます。このパイプラインは、環境ごとに適切なシークレットをロードします。シークレットを開発者に公開したり、コードを変更したりする必要はありません。

## バッチではなく、オンデマンドデータ向けに構築
<a name="on-demand-batches"></a>

多くの従来のシステムは、定期的に実行され、時間の経過と共に蓄積されたトランザクションのバッチを処理するように設計されています。例えば、銀行業務用のアプリケーションが 1 時間ごとに実行され、中央台帳で ATM トランザクションが処理される場合があります。Lambda ベースのアプリケーションでは、カスタム処理はすべてのイベントによってトリガーされる必要があり、必要に応じて同時実行数をスケールアップして、トランザクションをほぼリアルタイムで処理できます。

標準の Lambda 関数の実行時間は 15 分に制限されますが、耐久性のある関数は最大 1 年間実行できるため、長時間の処理ニーズに適しています。ただし、可能な場合は、バッチ処理よりもイベント駆動型処理を引き続き優先する必要があります。

Amazon EventBridge のルールで[スケジュールされた式を使用すると](https://docs.aws.amazon.com/eventbridge/latest/userguide/scheduled-events.html)、サーバーレスアプリケーションで [cron](https://en.wikipedia.org/wiki/Cron) タスクを実行できますが、これは控えめに使用するか、最後の手段として使用する必要があります。バッチを処理するスケジュールされたタスクでは、トランザクションの量が 15 分間の Lambda 時間制限内で処理できる量を超える可能性があります。外部システムの制限によりスケジューラを使用しなくてはならない場合は、通常、最短の妥当な繰り返し期間をスケジュールする必要があります。

例えば、Lambda 関数をトリガーするバッチプロセスを使用して、新しい Amazon S3 オブジェクトのリストを取得することはベストプラクティスではありません。これは、サービスが、15 分間の Lambda 関数内で処理できる数よりも多くの新しいオブジェクトをバッチ間で受け取る可能性があるためです。

![\[イベント駆動型アーキテクチャの図 10\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/event-driven-architectures-figure-10.png)


代わりに、新しいオブジェクトがバケットに配置されるたびに、Amazon S3 によって Lambda 関数が呼び出される必要があります。このアプローチは大幅にスケーラブルであり、ほぼリアルタイムで処理されます。

![\[イベント駆動型アーキテクチャの図 11\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/event-driven-architectures-figure-11.png)


## 複雑なワークフローのオーケストレーションオプションを選択する
<a name="orchestration"></a>

分岐ロジック、障害モデルのさまざまなタイプ、再試行ロジックを含むワークフローは、通常はオーケストレーターを使用して全体的な実行の状態を管理します。標準の Lambda 関数でアドホックオーケストレーションを構築しないでください。これにより、密結合で複雑なルーティングコードになり、自動状態復旧ができなくなります。

代わりに、次のいずれかの専用オーケストレーションオプションを使用します。
+ **[Lambda の耐久性のある関数](durable-functions.md):** 自動チェックポイント設定、組み込まれた再試行、および実行リカバリを備えた標準プログラミング言語を使用したアプリケーション中心のオーケストレーション。Lambda 内のビジネスロジックとともにコードにワークフローロジックを保持したいデベロッパーに最適です。
+ **[AWS Step Functions](with-step-functions.md):** 220 以上の AWS サービスへのネイティブ統合によるビジュアルワークフローオーケストレーション。マルチサービスの調整、メンテナンス不要のインフラストラクチャ、ビジュアルワークフロー設計に最適です。

これらのオプションの選択に関するガイダンスについては、「[耐久性のある関数か Step Functions か](durable-step-functions.md)」を参照してください。

[ Step Functions](https://aws.amazon.com/step-functions/) では、ステートマシンを使用してオーケストレーションを管理します。これにより、コードからエラー処理、ルーティング、分岐ロジックが抽出され、JSON を使用して宣言されたステートマシンに置き換えられます。ワークフローをより堅牢でオブザーバビリティにするだけでなく、ワークフローにバージョニングを追加し、ステートマシンをコードリポジトリに追加できるコード化されたリソースにすることもできます。

Lambda 関数のより簡単なワークフローが時間の経過とともに複雑化することは一般的です。本番稼働サーバーレスアプリケーションを運用する場合、このロジックをステートマシンまたは耐久性のある関数に移行できるように、この状況がいつ発生しているかを特定することが重要です。

## べき等性の実装
<a name="retries-failures"></a>

Lambda を含む AWS サーバーレスサービスには耐障害性があり、障害を処理するように設計されています。例えば、サービスが Lambda 関数を呼び出してサービス中断が発生した場合、Lambda は別のアベイラビリティーゾーンで関数を呼び出します。関数がエラーをスローした場合、Lambda は呼び出しを再試行します。

同じイベントが複数回受信される可能性があるため、関数は[べき等性](https://en.wikipedia.org/wiki/Idempotence)を持つように設計する必要があります。これは、同じイベントを複数回受信しても、イベントが最初に受信されたときと結果が変化しないことを意味します。

DynamoDB テーブルを使用して最近処理された識別子を追跡し、トランザクションが以前に既に処理されたかどうかを判断することにより、Lambda 関数にべき等性を実装できます。DynamoDB テーブルは、通常、[有効期限 (TTL)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) 値を実装し、項目を期限切れにすることで、使用されるストレージ領域を制限します。

## 複数の AWS アカウントを使用してクォータを管理する
<a name="multiple-accounts"></a>

AWS の多くの [Service Quotas](gettingstarted-limits.md) は、アカウントレベルで設定されます。ワークロードをさらに追加すると、制限を短時間で使い果たす可能性があることを意味します。

この問題を解決する効果的な方法は、複数の AWS アカウントを使用して各ワークロードをそれぞれのアカウント専用にすることです。これにより、クォータが他のワークロードや非本番稼働用リソースと共有されるのを防ぎます。

 さらに、[AWS 組織](https://aws.amazon.com/organizations/)を使用することにより、これらのアカウントの請求、コンプライアンス、セキュリティを一元的に管理できます。ポリシーをアカウントのグループにアタッチすると、カスタムスクリプトや手動プロセスを回避できます。

1 つの一般的なアプローチは、開発者それぞれに AWS アカウントを提供し、ベータデプロイステージと本番稼働用に個別のアカウントを使用する方法です。

![\[アプリケーション設計の図 3\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/application-design-figure-3.png)


このモデルでは、開発者はそれぞれアカウントに対して独自一連の制限があるため、その使用状況はお使いの本番稼働環境には影響しません。このアプローチにより、開発者は開発マシンに Lambda 関数を、個々のアカウントのライブクラウドリソースに対してローカルでテストできます。