AWS Step Functions를 사용하여 서버리스 Saga 패턴 구현 - AWS 권장 가이드

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

AWS Step Functions를 사용하여 서버리스 Saga 패턴 구현

작성자: Tabby Ward(AWS), Rohan Mehta(AWS) 및 Rimpy Tewani(AWS)

환경: PoC 또는 파일럿

기술: 현대화, 서버리스

워크로드: 오픈 소스

AWS 서비스: Amazon API Gateway, Amazon DynamoDB, AWS Lambda, Amazon SNS, AWS Step Functions

요약

마이크로서비스 아키텍처의 주요 목표는 분리되고 독립적인 구성 요소를 구축하여 애플리케이션의 민첩성, 유연성을 높이고 출시 시간을 단축하는 것입니다. 디커플링의 결과로 각 마이크로서비스 구성 요소에는 자체 데이터 지속성 계층이 있습니다. 분산 아키텍처에서는 비즈니스 트랜잭션이 여러 마이크로서비스에 걸쳐 있을 수 있습니다. 이러한 마이크로서비스는 단일 원자성, 일관성, 격리, 내구성(ACID) 트랜잭션을 사용할 수 없으므로 부분 트랜잭션이 발생할 수 있습니다. 이 경우 이미 처리된 트랜잭션을 취소하려면 일부 제어 로직이 필요합니다. 분산 사가 패턴은 일반적으로 이 목적에 사용됩니다. 

사가 패턴은 분산 애플리케이션의 일관성을 유지하고 여러 마이크로서비스 간의 트랜잭션을 조정하여 데이터 일관성을 유지하는 데 도움이 되는 장애 관리 패턴입니다. 사가 패턴을 사용하면 트랜잭션을 수행하는 모든 서비스가 이벤트를 게시하여 후속 서비스가 체인에서 다음 트랜잭션을 수행하도록 트리거합니다. 이는 체인의 마지막 거래가 완료될 때까지 계속됩니다. 비즈니스 트랜잭션이 실패할 경우, saga는 이전 트랜잭션에서 이루어진 변경 사항을 취소하는 일련의 보상 트랜잭션을 조정합니다.

이 패턴은 AWS Step Functions, AWS Lambda 및 Amazon DynamoDB와 같은 서버리스 기술을 사용하여 샘플 애플리케이션(여행 예약을 처리하는)의 설정 및 배포를 자동화하는 방법을 보여줍니다. 또한 샘플 애플리케이션은 Amazon API Gateway 및 Amazon Simple Notification Service(Amazon SNS)를 사용하여 saga 실행 조정자를 구현합니다. 이 패턴은 AWS 클라우드 개발 키트( ), 서버리스 애플리케이션 모델( ) 또는 Terraform과 같은 코드형 인프라(IaC SAM) 프레임워크와 함께 배포할 수 있습니다.AWS CDK AWS AWS

Saga 패턴 및 기타 데이터 지속성 패턴에 대한 자세한 내용은 AWS 규범적 지침 웹 사이트의 마이크로서비스에서 데이터 지속성 활성화 가이드를 참조하세요.

사전 조건 및 제한 사항

사전 조건 

  • 활성 상태의 AWS 계정.

  • AWS CloudFormation 스택을 생성할 수 있는 권한. 자세한 내용은 CloudFormation 설명서의 액세스 제어를 참조하세요.

  • 프레임워크를 사용하여 애플리케이션을 CLI 배포할 수 있도록 AWS 계정으로 구성된 선택한 IaC 프레임워크(AWS CDK AWS SAM, 또는 Terraform)입니다.

  • NodeJS는 애플리케이션을 빌드하고 로컬에서 실행하는 데 사용됩니다.

  • 원하는 코드 편집기(예: 비주얼 스튜디오 코드, 서브라임 또는 아톰)

제품 버전

제한 사항

이벤트 소싱은 모든 구성 요소가 느슨하게 결합되어 있고 서로에 대한 직접적인 지식이 없는 마이크로서비스 아키텍처에서 사가 오케스트레이션 패턴을 구현하는 자연스러운 방법입니다. 트랜잭션이 적은 단계(3~5개)를 포함하는 경우 사가 패턴이 매우 적합할 수 있습니다. 그러나 마이크로서비스 수와 단계 수에 따라 복잡성이 증가합니다. 

이 디자인을 사용하면 트랜잭션 패턴을 시뮬레이션하기 위해 모든 서비스를 실행해야 하므로 테스트 및 디버깅이 어려울 수 있습니다.

아키텍처

대상 아키텍처

제안된 아키텍처는 AWS Step Functions를 사용하여 saga 패턴을 구축하여 항공편을 예약하고, 렌터카를 예약하고, 휴가에 대한 결제를 처리합니다.

다음 워크플로 다이어그램은 여행 예약 시스템의 일반적인 흐름을 보여줍니다. 워크플로는 항공 여행 예약(“ReserveFlight), 차량 예약(“ReserveCarRental”), 결제 처리(“ProcessPayment”), 항공편 예약 확인(“ConfirmFlight”) 및 차량 대여 확인(“ConfirmCarRental”)으로 구성되며, 이 단계가 완료되면 성공 알림이 표시됩니다. 그러나 시스템에서 이러한 트랜잭션을 실행하는 중에 오류가 발생하면 역방향으로 실패하기 시작합니다. 예를 들어 결제 처리(“ProcessPayment”) 오류는 환불(“RefundPayment”)을 트리거한 다음 렌터카 및 항공편(“CancelRentalReservation” 및 “CancelFlightReservation”)의 취소를 트리거하여 실패 메시지로 전체 트랜잭션을 종료합니다.

이 패턴은 다이어그램에 강조 표시된 각 작업에 대해 별도의 Lambda 함수를 배포하고 항공편, 렌터카 및 결제를 위한 3개의 DynamoDB 테이블을 배포합니다. 각 Lambda 함수는 트랜잭션이 확인되었는지 또는 롤백되었는지에 따라 각 DynamoDB 테이블에서 행을 생성, 업데이트 또는 삭제합니다. 이 패턴은 AmazonSNS을 사용하여 구독자에게 텍스트(SMS) 메시지를 전송하여 실패하거나 성공한 트랜잭션을 알립니다. 

saga 패턴을 기반으로 한 여행 예약 시스템의 워크플로입니다.

자동화 및 규모 조정

IaC 프레임워크 중 하나를 사용하여 이 아키텍처의 구성을 생성할 수 있습니다. 원하는 IaC에 대한 다음 링크 중 하나를 사용합니다.

도구

AWS 서비스

  • AWS Step Functions는 AWS Lambda 함수와 기타 서비스를 결합하여 비즈니스 크리티컬 애플리케이션을 구축할 수 있는 서버리스 오케스트레이션 AWS 서비스입니다. Step Functions 그래픽 콘솔을 통해 애플리케이션의 워크플로를 일련의 이벤트 기반 단계로 볼 수 있습니다.

  • Amazon DynamoDB는 완전 관리형 NoSQL Database 서비스로, 원활한 확장성과 함께 빠르고 예측 가능한 성능을 제공합니다. DynamoDB를 사용하여 데이터 규모에 관계없이 데이터를 저장 및 검색하고, 어떤 수준의 요청 트래픽이라도 처리할 수 있는 데이터베이스 테이블을 생성할 수 있습니다.

  • AWS Lambda는 서버를 프로비저닝하거나 관리하지 않고도 코드를 실행할 수 있는 컴퓨팅 서비스입니다. Lambda는 필요 시에만 코드를 실행하며, 일일 몇 개의 요청에서 초당 수천 개의 요청까지 자동으로 규모를 조정합니다.

  • Amazon API Gateway는 모든 규모의 , 및 WebSocket APIs REST를 생성, 게시, 유지 관리HTTP, 모니터링 및 보호하기 위한 AWS 서비스입니다.

  • Amazon Simple Notification Service(Amazon SNS)는 게시자가 구독자에게 메시지를 전달하는 관리형 서비스입니다.

  • AWS Cloud Development Kit(AWS CDK)는 TypeScript,, Python JavaScript, Java 및 C#/와 같은 익숙한 프로그래밍 언어를 사용하여 클라우드 애플리케이션 리소스를 정의하는 소프트웨어 개발 프레임워크입니다.순.

  • AWS 서버리스 애플리케이션 모델(AWS SAM)은 서버리스 애플리케이션을 구축하기 위한 오픈 소스 프레임워크입니다. 함수, APIs, 데이터베이스 및 이벤트 소스 매핑을 표현하는 간단한 구문을 제공합니다.

코드

IaC 템플릿(AWS , CDK AWS SAM또는 Terraform), Lambda 함수 및 DynamoDB 테이블을 포함하여 saga 패턴을 보여주는 샘플 애플리케이션의 코드는 다음 링크에서 찾을 수 있습니다. 이를 설치하려면 첫 번째 에픽의 지침을 따르세요.

에픽

작업설명필요한 기술

NPM 패키지를 설치합니다.

새 디렉터리를 생성하고 터미널에서 해당 디렉터리로 이동한 다음 이 패턴의 앞부분에 있는 코드 섹션에서 선택한 GitHub 리포지토리를 복제합니다.

package.json 파일이 있는 루트 폴더에서 다음 명령을 실행하여 모든 Node Package Manager(NPM) 패키지를 다운로드하고 설치합니다.

npm install
개발자, 클라우드 아키텍트

스크립트를 컴파일합니다.

루트 폴더에서 다음 명령을 실행하여 TypeScript 트랜스파일러에 필요한 모든 JavaScript 파일을 생성하도록 지시합니다.

npm run build
개발자, 클라우드 아키텍트

변경 사항을 확인하고 다시 컴파일하세요.

루트 폴더에서 별도의 터미널 창에서 다음 명령을 실행하여 코드 변경을 관찰하고 변경 사항이 감지되면 코드를 컴파일합니다.

npm run watch
개발자, 클라우드 아키텍트

단위 테스트를 실행합니다(AWSCDK만 해당).

를 사용하는 경우 루트 폴더AWSCDK에서 다음 명령을 실행하여 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.

배포가 완료된 후 콘솔에 URL 표시되는 API 게이트웨이에 유의하세요. 사가 실행 흐름을 테스트하려면 이 정보가 필요합니다.

개발자, 클라우드 아키텍트

배포된 스택을 현재 상태와 비교합니다.

루트 폴더에서 다음 명령을 실행하여 소스 코드를 변경한 후 배포된 스택을 현재 상태와 비교합니다.

AWS CDK:

cdk diff

AWS SAM:

sam deploy

Terraform:

terraform plan
개발자, 클라우드 아키텍트
작업설명필요한 기술

사가 실행 흐름을 테스트합니다.

스택을 배포할 때 이전 단계에서 기록URL한 API 게이트웨이로 이동합니다. 그러면 URL 상태 시스템이 시작됩니다. 다른 URL 파라미터를 전달하여 상태 시스템의 흐름을 조작하는 방법에 대한 자세한 내용은 추가 정보 섹션을 참조하세요.

결과를 보려면 AWS 관리 콘솔에 로그인하고 Step Functions 콘솔로 이동합니다. 여기에서 사가 스테이트 머신의 모든 단계를 볼 수 있습니다. 또한 DynamoDB 테이블을 보고 삽입, 업데이트 또는 삭제된 레코드를 확인할 수 있습니다. 화면을 자주 새로고침하면 트랜잭션 상태가 pending에서 confirmed로 변경되는 것을 볼 수 있습니다. 

예약 성공 또는 실패 시 SMS 메시지를 수신하도록 stateMachine.ts 파일의 코드를 휴대폰 번호로 업데이트하여 SNS 주제를 구독할 수 있습니다. 자세한 내용은 추가 정보 섹션의 AmazonSNS을 참조하세요.

개발자, 클라우드 아키텍트
작업설명필요한 기술

리소스를 정리합니다.

이 응용 프로그램에 배포된 리소스를 정리하려면 다음 명령 중 하나를 사용하시면 됩니다.

AWS CDK:

cdk destroy

AWS SAM:

sam delete

Terraform:

terraform destroy
앱 개발자, 클라우드 아키텍트

관련 리소스

기술 문서

AWS 서비스 설명서

자습서

추가 정보

코드

테스트 목적으로 이 패턴은 API Gateway와 Step Functions 상태 시스템을 트리거하는 테스트 Lambda 함수를 배포합니다. Step Functions를 사용하면 run_type 파라미터를 전달하여 “,” “,” “ReserveFlight,ReserveCarRental” “ProcessPayment,” “ConfirmFlight,” “의 실패를 모방하여 여행 예약 시스템의 기능을 제어할 수 있습니다ConfirmCarRental.

saga Lambda 함수(sagaLambda.ts)는 API 게이트웨이 의 쿼리 파라미터에서 입력을 가져와서 다음 JSON 객체를 URL생성하고 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 게이트웨이 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에서 상태 머신 플로우 및 실행을 지원하기 위해 다음 함수가 생성됩니다.

  • 항공편 예약: 항공편을 예약하기 위해 DynamoDB 항공편 테이블에 pendingtransaction_status에 대한 레코드를 삽입합니다.

  • 항공편 확인: DynamoDB Flights 테이블의 기록을 업데이트하여 transaction_status에서 confirmed으로 설정하고 항공편을 확인합니다.

  • 항공편 예약 취소: DynamoDB 항공편 테이블에서 기록을 삭제하여 보류 중인 항공편을 취소합니다.

  • 렌터카 예약 : DynamoDB CarRentals 테이블에 레코드를 transaction_status 의 로 삽입pending하여 렌터카를 예약합니다.

  • 렌터카 확인 : DynamoDB CarRentals 테이블의 레코드를 업데이트하여 transaction_status로 설정하고 렌터카를 confirmed확인합니다.

  • 렌터카 예약 취소: DynamoDB CarRentals 테이블에서 레코드를 삭제하여 보류 중인 렌터카를 취소합니다.

  • 결제 처리: 결제를 위해 DynamoDB 결제 테이블에 레코드를 삽입합니다.

  • 결제 취소: DynamoDB 결제 테이블에서 결제에 대한 레코드를 삭제합니다.

Amazon SNS

샘플 애플리케이션은 SMS 메시지를 보내고 고객에게 성공하거나 실패한 예약에 대해 알리기 위해 다음 주제와 구독을 생성합니다. 샘플 애플리케이션을 테스트하는 동안 문자 메시지를 받으려면 상태 시스템 정의 파일에서 유효한 전화번호로 SMS 구독을 업데이트합니다.

AWS CDK 스니펫(다음 코드의 두 번째 줄에 전화번호 추가):

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에서 구현한 실패한 예약의 예입니다.