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

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

AWS Step Functions을 사용하여 서버리스 사가 패턴 구현

작성자: 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(SNS)를 사용합니다. 패턴은 AWS Cloud Development Kit(AWS CDK), AWS Serverless Application Model AWS SAM) 또는 Terraform과 같은 코드형 인프라(IaC) 프레임워크와 함께 배포할 수 있습니다.

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

사전 조건 및 제한 사항

사전 조건 

  • 활성 상태의 AWS 계정.

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

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

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

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

제품 버전

제한 사항

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

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

 

아키텍처

대상 아키텍처

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

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

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

자동화 및 규모 조정

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

도구

서비스

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

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

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

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

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

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

  • AWS Serverless Application Model(AWS SAM)은 서버리스 애플리케이션을 빌드하는 데 사용할 수 있는 오픈소스 프레임워크입니다. 함수, API, 데이터베이스 및 이벤트 소스 매핑을 표현하는 속기 구문을 제공합니다.

코드

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

에픽

작업설명필요한 기술

NPM 패키지를 설치합니다.

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

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

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

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

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

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

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

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

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

유닛 테스트를 실행합니다(AWS CDK만 해당).

AWS CDK를 사용하는 경우 루트 폴더에서 다음 명령을 실행하여 Jest 유닛 테스트를 수행하세요.

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

데모 스택을 AWS에 배포합니다.

중요: 애플리케이션은 AWS 리전에 구애받지 않습니다. 프로파일을 사용하는 경우 AWS Command Line Interface(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 Gateway URL을 기록합니다. 사가 실행 흐름을 테스트하려면 이 정보가 필요합니다.

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

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

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

AWS CDK:

cdk diff

AWS SAM:

sam deploy

Terraform:

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

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

이전 단계에서 스택을 배포할 때 기록해 둔 API Gateway URL로 이동합니다. 이 URL은 상태 머신 시작을 트리거합니다. 다양한 URL 파라미터를 전달하여 상태 머신의 흐름을 조작하는 방법에 대한 자세한 내용은 추가 정보 섹션을 참조하세요.

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

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

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

리소스를 정리합니다.

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

AWS CDK:

cdk destroy

AWS SAM:

sam delete

Terraform:

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

관련 리소스

기술 문서

AWS 서비스 설명서

자습서

추가 정보

코드

테스트 목적으로 이 패턴은 API Gateway와 Step Functions 상태 머신을 트리거하는 테스트 Lambda 함수를 배포합니다. Step Functions를 사용하면 “,”, “,” “”, “” ReserveFlightReserveCarRental, “” 등의 오류를 모방하는 run_type 매개변수를 전달하여 여행 예약 시스템의 기능을 제어할 수 ConfirmCarRental 있습니다. ProcessPayment ConfirmFlight

saga Lambda 함수(sagaLambda.ts)는 API Gateway 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 게이트웨이 url}? 런타입= failFlightsReservation

  • 비행 실패 확인 ─ https://{api 게이트웨이 URL}? 런타입= failFlightsConfirmation

  • 렌터카 예약 실패 ─ https://{api 게이트웨이 URL}? 실행 유형= 예약 failCarRental

  • 렌터카 실패 확인 ─ https://{api 게이트웨이 URL}? 실행 유형= 확인 failCarRental

  • 결제 처리 실패 ─ 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에서 상태 머신 플로우 및 실행을 지원하기 위해 다음 함수가 생성됩니다.

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

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

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

  • 렌터카 예약: 렌터카를 예약하기 위해 레코드를 CarRentals DynamoDB 테이블에 +와 함께 transaction_status 삽입합니다. pending

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

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

  • 결제 처리: 결제를 위해 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 메시지를 통해 예약 성공 여부를 고객에게 알립니다.

예약 실패

이 흐름은 사가 패턴의 실패 사례입니다. 항공편 및 렌터카를 예약한 후 “ProcessPayment" 이 (가) 실패하면 단계가 역순으로 취소됩니다.  예약이 취소되고 SNS 주제 구독자에게 전송되는 SMS 메시지를 통해 고객에게 실패 사실을 알립니다.