AWS Step Functions を使用してサーバーレス Saga パターンを実装する - AWS 規範ガイダンス

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

AWS Step Functions を使用してサーバーレス Saga パターンを実装する

作成者: Tabby Ward (AWS)、Rohan Mehta (AWS)、Rimpy Tewani (AWS)

環境:PoC またはパイロット

テクノロジー: モダナイゼーション、サーバーレス

ワークロード: オープンソース

AWS サービス: Amazon API Gateway、Amazon DynamoDBAWSLambda、Amazon、SNSAWSStep Functions

[概要]

マイクロサービスアーキテクチャの主な目標は、アプリケーションの俊敏性、柔軟性、および市場投入までの時間を短縮するために、分離された独立したコンポーネントを構築することです。デカップリングにより、各マイクロサービスコンポーネントには独自のデータ永続化レイヤーが設けられます。分散型アーキテクチャでは、ビジネストランザクションが複数のマイクロサービスにまたがる可能性があります。これらのマイクロサービスは単一のアトミック性、一貫性、分離性、耐久性 (ACID) トランザクションを使用できないため、部分的なトランザクションになる可能性があります。この場合、すでに処理されたトランザクションを元に戻すには、何らかの制御ロジックが必要です。ディストリビュートサガパターンは、通常、この目的のために使用されます。 

サガパターンは、分散アプリケーションの一貫性を確立し、複数のマイクロサービス間のトランザクションを調整してデータ整合性を維持するのに役立つ障害管理パターンです。サガパターンを使用すると、トランザクションを実行するすべてのサービスがイベントをパブリッシュし、後続のサービスがチェーン内の次のトランザクションを実行するようトリガーします。これはチェーン内の最後のトランザクションが完了するまで続きます。ビジネストランザクションが失敗した場合、sagaは一連の補償トランザクションを組織し、それまでのトランザクションによって行われた変更を取り消します。

このパターンは、AWSStep Functions、AWSLambda、Amazon DynamoDB などのサーバーレステクノロジーを使用して、サンプルアプリケーション (旅行予約を処理する) のセットアップとデプロイを自動化する方法を示しています。サンプルアプリケーションでは、Amazon API Gateway と Amazon Simple Notification Service (Amazon SNS) も使用して、Saga 実行コーディネーターを実装します。このパターンは、 AWS クラウド開発キット ( )、AWSサーバーレスアプリケーションモデル (AWS CDK)、Terraform などの Infrastructure as Code (AWSIaC SAM) フレームワークを使用してデプロイできます。

Saga パターンやその他のデータ永続性パターンの詳細については、 AWS 規範ガイダンスウェブサイトの「マイクロサービスでデータ永続性を有効にする」ガイドを参照してください。

前提条件と制限

前提条件

  • アクティブ AWS アカウント。

  • AWS CloudFormation スタックを作成するアクセス許可。詳細については、 CloudFormation ドキュメントの「アクセスの制御」を参照してください。

  • 任意の IaC フレームワーク (AWSCDK、SAM、または AWS Terraform) をAWSアカウントで設定し、フレームワークを使用してアプリケーションをCLIデプロイできるようにします。

  • NodeJSは、アプリケーションの構築とローカルでの実行に使用されます。

  • 任意のコードエディター (Visual Studio Code、Sublime、Atom など)。

製品バージョン

制約事項

イベントソーシングは、すべてのコンポーネントがゆるく結合されていて互いに直接認識できないマイクロサービスアーキテクチャに saga オーケストレーションパターンを実装する自然な方法です。トランザクションのステップ数が少ない (3 ~ 5) 場合は、サガパターンが最適かもしれません。ただし、マイクロサービスの数とステップの数が増えるにつれて、複雑さも増します。 

この設計を使用すると、トランザクションパターンをシミュレートするためにすべてのサービスを実行する必要があるため、テストとデバッグが難しくなる可能性があります。

アーキテクチャ

ターゲットアーキテクチャ

提案されたアーキテクチャでは、AWSStep Functions を使用して、フライトの予約、レンタカーの予約、休暇の支払い処理を行うための saga パターンを構築します。

以下のワークフロー図は、旅行予約システムの一般的なフローを示しています。ワークフローは、航空旅行の予約 (ReserveFlight「」)、車の予約 (ReserveCarRental「」)、支払いの処理 (ProcessPayment「」)、フライト予約の確認 (ConfirmFlightConfirmCarRental「」)、およびこれらのステップが完了したときの成功通知の確認で構成されます。ただし、これらのトランザクションのいずれかを実行中にエラーが発生すると、システムは逆方向にフェイルオーバーし始めます。例えば、支払い処理 (ProcessPayment「」) のエラーにより返金 (RefundPayment「」) がトリガーされ、レンタカーとフライトのキャンセル (CancelRentalReservation「」とCancelFlightReservation「」) がトリガーされ、トランザクション全体が失敗メッセージで終了します。

このパターンでは、図で強調表示されているタスクごとに個別の Lambda 関数がデプロイされるほか、フライト、レンタカー、支払い用の 3 つの DynamoDB テーブルもデプロイされます。各 Lambda 関数は、トランザクションが確認されたかロールバックされたかに応じて、それぞれの DynamoDB テーブルの行を作成、更新、または削除します。このパターンでは、Amazon を使用してサブスクライバーSNSにテキスト (SMS) メッセージを送信し、失敗したトランザクションまたは成功したトランザクションを通知します。 

Saga パターンに基づく旅行予約システムのワークフロー。

自動化とスケール

IaC フレームワークのいずれかを使用して、このアーキテクチャの構成を作成できます。お好みの Iac について、以下のリンクの 1 つを使用します。

ツール

AWS サービス

  • AWS Step Functions は、Lambda AWS 関数と他の サービスを組み合わせてビジネスクリティカルなアプリケーションを構築できるサーバーレスオーケストレーションAWSサービスです。Step Functions のグラフィカルコンソールでは、アプリケーションのワークフローを一連のイベント駆動型ステップとして確認できます。

  • Amazon DynamoDB はフルマネージド型の NoSQL データベースサービスで、高速で予測可能なパフォーマンスとシームレスなスケーラビリティを提供します。DynamoDB を使用して、任意の量のデータを保存および取得できるデータベーステーブルを作成し、任意のレベルのリクエストトラフィックを処理できます。

  • AWS Lambda は、サーバーのプロビジョニングや管理を行わずにコードを実行できるようにするコンピューティングサービスです。Lambda は必要に応じてコードを実行し、1 日あたり数個のリクエストから 1 秒あたり数千のリクエストまで自動的にスケールします。

  • Amazon API Gateway は、、、および をあらゆる規模で作成、公開REST、保守、モニタリングHTTP、 WebSocket APIs保護するための AWSサービスです。

  • Amazon Simple Notification Service (Amazon SNS) は、パブリッシャーからサブスクライバーへのメッセージ配信を提供するマネージドサービスです。

  • AWS Cloud Development Kit (AWS CDK) は、、、Python TypeScript、Java JavaScript、C#/ などの使い慣れたプログラミング言語を使用してクラウドアプリケーションリソースを定義するためのソフトウェア開発フレームワークです。Net。

  • AWS サーバーレスアプリケーションモデル (AWS SAM) は、サーバーレスアプリケーションを構築するためのオープンソースフレームワークです。関数、、データベースAPIs、イベントソースマッピングを表す短縮構文を提供します。

コード

IaC テンプレート (AWS、、または Terraform)、Lambda 関数CDKAWSSAM、DynamoDB テーブルなど、Saga パターンを示すサンプルアプリケーションのコードは、次のリンクにあります。最初のエピックの指示に従って、これらをインストールします。

エピック

タスク説明必要なスキル

NPM パッケージをインストールします。

新しいディレクトリを作成し、ターミナルでそのディレクトリに移動し、このパターンの前半のコードセクションから選択した GitHub リポジトリのクローンを作成します。

package.json ファイルがあるルートフォルダで、次のコマンドを実行して、すべての Node Package Manager (NPM) パッケージをダウンロードしてインストールします。

npm install
開発者、クラウドアーキテクト

Compile Script

ルートフォルダで、次のコマンドを実行して、必要なすべての JavaScript ファイルを作成するように TypeScript トランスパイルに指示します。

npm run build
開発者、クラウドアーキテクト

変更を監視して再コンパイルする。

ルートフォルダーで、別のターミナルウィンドウで次のコマンドを実行してコードの変更を監視し、変更が検出されたらコードをコンパイルします。

npm run watch
開発者、クラウドアーキテクト

ユニットテストを実行します (AWS CDKのみ)。

を使用している場合はAWSCDK、ルートフォルダで次のコマンドを実行して Jest ユニットテストを実行します。

npm run test
開発者、クラウドアーキテクト
タスク説明必要なスキル

デモスタックを にデプロイしますAWS。

重要: アプリケーションはAWSリージョンに依存しません。プロファイルを使用する場合は、AWSコマンドラインインターフェイス (AWS CLI) プロファイルまたはAWSCLI環境変数を使用してリージョンを明示的に宣言する必要があります。

ルートフォルダで、次のコマンドを実行してデプロイアセンブリを作成し、デフォルトのAWSアカウントとリージョンにデプロイします。

AWS CDK:

cdk bootstrap cdk deploy

AWS SAM:

sam build sam deploy --guided

Terraform

terraform init terraform apply

この処理は、完了まで数分、またはそれ以上かかる場合があります。このコマンドは、 AWS 用に設定されたデフォルトの認証情報を使用しますCLI。

デプロイが完了した後にコンソールURLに表示されるAPIゲートウェイを書き留めます。この情報は Saga 実行フローをテストする際に必要になります。

開発者、クラウドアーキテクト

デプロイされたスタックを現在の状態と比較します。

ルートフォルダーで以下のコマンドを実行して、ソースコードに変更を加えた後、デプロイされたスタックを現在の状態と比較します。

AWS CDK:

cdk diff

AWS SAM:

sam deploy

Terraform

terraform plan
開発者、クラウドアーキテクト
タスク説明必要なスキル

Saga 実行フローをテストします。

スタックをデプロイしたときに、前のステップでメモURLしたAPIゲートウェイに移動します。これによりURL、ステートマシンが開始されます。さまざまなURLパラメータを渡してステートマシンのフローを操作する方法の詳細については、「追加情報」セクションを参照してください。

結果を表示するには、 AWSマネジメントコンソールにサインインし、Step Functions コンソールに移動します。ここでは、Saga ステートマシンのすべてのステップを確認できます。DynamoDB テーブルを表示して、挿入、更新、削除されたレコードを確認することもできます。画面を頻繁に更新すると、トランザクションのステータスがpendingからconfirmedに変わるのを確認できます。 

予約が成功または失敗したときにSMSメッセージを受信するようにstateMachine.ts、 ファイル内のコードを携帯電話番号で更新することで、SNSトピックをサブスクライブできます。詳細については、「追加情報」セクションの「AmazonSNS」を参照してください。 追加情報

開発者、クラウドアーキテクト
タスク説明必要なスキル

リソースをクリーンアップします。

このアプリケーションにデプロイされたリソースをクリーンアップするには、次のコマンドの 1 つを使用します。

AWS CDK:

cdk destroy

AWS SAM:

sam delete

Terraform

terraform destroy
アプリ開発者、クラウドアーキテクト

関連リソース

テクニカルペーパー

AWS サービスドキュメント

チュートリアル

追加情報

コード

テスト目的で、このパターンは API Gateway と Step Functions ステートマシンをトリガーするテスト Lambda 関数をデプロイします。Step Functions を使用すると、「」、ReserveFlight「」、「」、「」の障害を模倣するrun_typeパラメータを渡すことでReserveCarRentalProcessPaymentConfirmFlight、旅行予約システムの機能を制御できますConfirmCarRental。

saga Lambda 関数 (sagaLambda.ts) は、APIゲートウェイ のクエリパラメータから入力を受け取りURL、次のJSONオブジェクトを作成し、実行のために Step Functions に渡します。

let input = { "trip_id": tripID, // value taken from query parameter, default is AWS request ID "depart_city": "Detroit", "depart_time": "2021-07-07T06:00:00.000Z", "arrive_city": "Frankfurt", "arrive_time": "2021-07-09T08:00:00.000Z", "rental": "BMW", "rental_from": "2021-07-09T00:00:00.000Z", "rental_to": "2021-07-17T00:00:00.000Z", "run_type": runType // value taken from query parameter, default is "success" };

次のURLパラメータを渡すことで、Step Functions ステートマシンのさまざまなフローを試すことができます。

  • 実行成功 ─ https://{api gateway url}

  • 予約フライト失敗 ─ https://{api gateway url}?runType=failFlightsReservation

  • フライト失敗の確認 ─ https://{api gateway url}?runType=failFlightsConfirmation

  • 予約レンタカーの失敗 ─ https://{api gateway url}?runType= failCarRental予約

  • レンタカーの失敗の確認 ─ https://{api gateway url}?runType=failCarRental確認

  • 支払い処理の失敗 ─ https://{api gateway url}?runType=failPayment

  • トリップ ID ─ https://{api gateway url}?tripID ={デフォルトでは、トリップ ID はAWSリクエスト ID} になります

IaC テンプレート

リンクされたリポジトリには、サンプル旅行予約アプリケーション全体を作成するのに使用できる IaC テンプレートが含まれています。

DynamoDB テーブル

フライト、レンタカー、支払いテーブルのデータモデルは次のとおりです。

Flight Data Model: var params = { TableName: process.env.TABLE_NAME, Item: { 'pk' : {S: event.trip_id}, 'sk' : {S: flightReservationID}, 'trip_id' : {S: event.trip_id}, 'id': {S: flightReservationID}, 'depart_city' : {S: event.depart_city}, 'depart_time': {S: event.depart_time}, 'arrive_city': {S: event.arrive_city}, 'arrive_time': {S: event.arrive_time}, 'transaction_status': {S: 'pending'} } }; Car Rental Data Model: var params = { TableName: process.env.TABLE_NAME, Item: { 'pk' : {S: event.trip_id}, 'sk' : {S: carRentalReservationID}, 'trip_id' : {S: event.trip_id}, 'id': {S: carRentalReservationID}, 'rental': {S: event.rental}, 'rental_from': {S: event.rental_from}, 'rental_to': {S: event.rental_to}, 'transaction_status': {S: 'pending'} } }; Payment Data Model: var params = { TableName: process.env.TABLE_NAME, Item: { 'pk' : {S: event.trip_id}, 'sk' : {S: paymentID}, 'trip_id' : {S: event.trip_id}, 'id': {S: paymentID}, 'amount': {S: "750.00"}, // hard coded for simplicity as implementing any monetary transaction functionality is beyond the scope of this pattern 'currency': {S: "USD"}, 'transaction_status': {S: "confirmed"} } };

Lambda 関数

Step Functions でのステートマシンフローと実行をサポートするために、以下の関数が作成されます。

  • フライトを予約:フライトを予約するために、transaction_statuspendingであるレコードをDynamoDB Flightsテーブルに挿入します。

  • フライトを確認:DynamoDB フライトテーブルのレコードを更新してtransaction_statusconfirmedに設定し、フライトを確認します。

  • フライト予約をキャンセル:DynamoDB フライトテーブルからレコードを削除して、保留中のフライトをキャンセルします。

  • レンタカーの予約: DynamoDB CarRentals テーブルにレコードを transaction_statusの で挿入しpending、レンタカーを予約します。

  • レンタカーの確認: DynamoDB CarRentals テーブルのレコードを更新し、 を transaction_statusに設定してconfirmed、レンタカーを確認します。

  • レンタカー予約のキャンセル: DynamoDB CarRentals テーブルからレコードを削除して、保留中のレンタカーをキャンセルします。

  • 支払い処理:支払いのレコードを DynamoDB 支払いテーブルに挿入します。

  • 支払いをキャンセル:DynamoDB ペイメントテーブルから支払いのレコードを削除します。

Amazon SNS

サンプルアプリケーションは、SMSメッセージを送信し、予約の成功または失敗を顧客に通知するための次のトピックとサブスクリプションを作成します。サンプルアプリケーションのテスト中にテキストメッセージを受信する場合は、ステートマシン定義ファイルの有効な電話番号でSMSサブスクリプションを更新します。

AWS CDK スニペット (次のコードの 2 行目に電話番号を追加します)。

const topic = new sns.Topic(this, 'Topic'); topic.addSubscription(new subscriptions.SmsSubscription('+11111111111')); const snsNotificationFailure = new tasks.SnsPublish(this ,'SendingSMSFailure', { topic:topic, integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, message: sfn.TaskInput.fromText('Your Travel Reservation Failed'), }); const snsNotificationSuccess = new tasks.SnsPublish(this ,'SendingSMSSuccess', { topic:topic, integrationPattern: sfn.IntegrationPattern.REQUEST_RESPONSE, message: sfn.TaskInput.fromText('Your Travel Reservation is Successful'), });

AWS SAM スニペット (+1111111111文字列を有効な電話番号に置き換えてください)。

StateMachineTopic11111111111: Type: 'AWS::SNS::Subscription' Properties: Protocol: sms TopicArn: Ref: StateMachineTopic Endpoint: '+11111111111' Metadata: 'aws:sam:path': SamServerlessSagaStack/StateMachine/Topic/+11111111111/Resource

Terraform スニペット (+111111111文字列を有効な電話番号に置き換える):

resource "aws_sns_topic_subscription" "sms-target" { topic_arn = aws_sns_topic.topic.arn protocol = "sms" endpoint = "+11111111111" }

予約成功

次のフローは、ReserveFlight「」、ReserveCarRental「」、「」の後にProcessPayment「」、ConfirmFlight「」が続く予約が成功したことを示していますConfirmCarRental。SNS トピックのサブスクライバーに送信されるSMSメッセージを通じて、予約が成功したことがお客様に通知されます。

Saga パターンを使用して Step Functions によって実装された予約の成功の例。

予約失敗

このフローは、サガ・パターンの失敗の一例です。フライトとレンタカーの予約後にProcessPayment「」が失敗すると、ステップは逆の順序でキャンセルされます。 予約がリリースされ、SNSトピックのサブスクライバーに送信されるSMSメッセージを通じて、お客様に障害が通知されます。

Saga パターンを使用して Step Functions によって実装された失敗した予約の例。