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

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

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

タビー・ウォード(AWS)、ローハン・メータ(AWS)、リンピー・テワニ(AWS)によって作成された

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

テクノロジー:モダナイゼーション、サーバーレス、クラウドネイティブ

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

AWS サービス:Amazon API Gateway、Amazon DynamoDB、AWS Lambda、Amazon SNS、AWS Step Functions

[概要]

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

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

このパターンは、AWS Step Functions、AWS Lambda、Amazon DynamoDB などのサーバーレステクノロジーを使用して、サンプルアプリケーション (旅行の予約を処理する) の設定とデプロイを自動化する方法を示しています。サンプルアプリケーションでは、Saga 実行コーディネーターを実装するために Amazon API Gateway と Amazon Simple Notification Service (Amazon SNS) も使用します。パターンは、AWS Cloud Development Kit (AWS CDK)、AWS サーバーレスアプリケーションモデル (AWS SAM)、Terraform などのinfrastructure as code (IaC フレームワークを使用してデプロイできます。

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

前提条件と制限

前提条件

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

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

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

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

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

製品バージョン

制約事項

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

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

 

アーキテクチャ

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

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

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

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

自動化とスケール

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

ツール

AWS サービス

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

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

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

  • Amazon API Gateway は、あらゆる規模の REST、HTTP、API WebSocket APIs。

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

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

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

Code

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

エピック

タスク説明必要なスキル

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

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

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

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

Compile Script

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

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

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

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

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

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

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

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

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

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

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

AWS CDK

cdk bootstrap cdk deploy

AWS SAM

sam build sam deploy --guided

Terraform

terraform init terraform apply

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

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

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

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

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

AWS CDK

cdk diff

AWS SAM

sam deploy

Terraform

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

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

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

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

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

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

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

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

AWS CDK

cdk destroy

AWS SAM

sam delete

Terraform

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

関連リソース

テクニカルペーパー

AWS サービスのドキュメント

チュートリアル

追加情報

Code

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

sagaLambda 関数 (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 =failCarRentalConfirmation

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

  • トリップ ID を渡す ─ https://{api gateway url}?tripID={by default, trip ID will be the AWS request 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 フライトテーブルからレコードを削除して、保留中のフライトをキャンセルします。

  • 予約車: レコードを transaction_statusの DynamoDB CarRentals テーブルに挿入して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 メッセージを通じてお客様に通知されます。

予約失敗

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