왜 서버리스 아키텍처를 배울까?
여러분이 스타트업의 백엔드 개발자라고 상상해 보세요. CEO가 새로운 주문 처리 시스템을 만들어 달라고 합니다. 요구사항은 이렇습니다:

- 고객이 주문을 하면 데이터 검증 (가격, 재고, 주소 형식)
- 검증 통과 시 결제 처리 (외부 PG사 API 호출)
- 결제 성공 시 확인 이메일 발송
- 어느 단계에서든 실패하면 자동 재시도, 그래도 실패하면 관리자에게 알림
전통적인 방식이라면 EC2 서버를 띄우고, 워커 프로세스를 관리하고, 메시지 큐를 직접 운영해야 합니다. 서버가 다운되면? 트래픽이 갑자기 10배로 늘면? 이 모든 상황에 대한 대비를 직접 해야 합니다.
서버리스 아키텍처는 이 모든 인프라 관리 부담을 AWS에 맡기고, 개발자는 비즈니스 로직에만 집중하는 접근법입니다.
이 실습에서 만들 시스템의 핵심 서비스 역할은 다음과 같습니다:
| 서비스 | 역할 | 전통 방식 대체 |
|---|---|---|
| Lambda | 각 단계의 비즈니스 로직 실행 | EC2 + 애플리케이션 서버 |
| Step Functions | 워크플로 순서 제어 + 에러 핸들링 | 직접 구현한 오케스트레이터 |
| SQS | 비동기 메시지 전달 + 버퍼링 | RabbitMQ / Redis Queue |
| SNS | 이벤트 알림 (이메일, SMS) | 직접 구현한 알림 시스템 |
오늘 이 네 가지 서비스를 조합하여 프로덕션 수준의 서버리스 워크플로를 직접 구축해 보겠습니다.
실습을 시작하기 전에 AWS 콘솔에 로그인되어 있는지 확인하세요. 리전은 ap-northeast-2 (서울) 을 사용합니다.
아키텍처 개요

서버리스 워크플로
비용 예측
비용 계산기
100만 요청당 $0.20 + 실행시간
상태 전환 1,000당 $0.025
요청 100만당 $0.40
요청 100만당 $0.50
* 실제 비용은 AWS 요금 정책에 따라 달라질 수 있습니다.
Step 1: Lambda 함수 작성
먼저 워크플로의 각 단계를 담당할 Lambda 함수 3개를 만듭니다. 각 함수는 독립적으로 동작하며, Step Functions가 순서를 제어합니다.
- Lambda 콘솔 → 함수 생성 → 새로 작성
- 함수 이름:
lab-serverless-validate, 런타임: Python 3.12 - 아래 코드를 붙여넣습니다 — 입력 데이터의 필수 필드를 검증하고 결과를 반환합니다:
코드
def lambda_handler(event, context): required = ['name', 'email', 'amount'] missing = [f for f in required if f not in event] if missing: raise ValueError(f"필수 필드 누락: {', '.join(missing)}") if event['amount'] <= 0: raise ValueError("금액은 0보다 커야 합니다") return {**event, 'validated': True, 'step': 'validate'} - Deploy 클릭 후, 테스트 탭에서
{"name":"홍길동","email":"test@example.com","amount":10000}입력 후 실행 - 같은 방식으로
lab-serverless-process함수 생성 — 결제를 시뮬레이션합니다:코드import uuid, datetime def lambda_handler(event, context): return {**event, 'orderId': str(uuid.uuid4())[:8], 'processedAt': datetime.datetime.now().isoformat(), 'step': 'process'} lab-serverless-notify함수 생성 — 처리 결과를 요약합니다:코드def lambda_handler(event, context): return {'message': f"주문 {event['orderId']} 처리 완료", 'email': event['email'], 'step': 'notify'}- 세 함수 모두 테스트 이벤트로 동작 확인
# 예시: validate 함수 생성
aws lambda create-function \
--function-name lab-serverless-validate \
--runtime python3.12 \
--role arn:aws:iam::ACCOUNT_ID:role/lambda-execution-role \
--handler lambda_function.lambda_handler \
--zip-file fileb://validate.zipStep 2: Step Functions 상태 머신 설계
Step Functions는 Lambda 함수들의 실행 순서, 에러 핸들링, 재시도 정책을 시각적으로 관리합니다.
- 1AWS 콘솔에서 Step Functions 검색 후 클릭
- 2상태 머신 생성 클릭
- 3코드로 작성 선택 (Workflow Studio보다 정확한 제어 가능)
- 4유형: 표준 선택 (Express는 5분 이내 작업에 적합)
- 5정의에 아래 ASL(Amazon States Language) JSON을 붙여넣습니다: { "StartAt": "ValidateInput", "States": { "ValidateInput": { "Type": "Task", "Resource": "arn:aws:lambda:ap-northeast-2:ACCOUNT_ID:function:lab-serverless-validate", "Next": "ProcessOrder", "Retry": [{"ErrorEquals": ["States.TaskFailed"], "MaxAttempts": 2, "BackoffRate": 2}], "Catch": [{"ErrorEquals": ["States.ALL"], "Next": "HandleError"}] }, "ProcessOrder": { "Type": "Task", "Resource"
- 6ACCOUNT_ID를 본인의 AWS 계정 ID로 교체합니다 (콘솔 우측 상단에서 확인)
- 7이름: lab-serverless-workflow → 상태 머신 생성 클릭
- 8실행 역할은 새 역할 생성 선택 — Step Functions가 Lambda를 호출할 권한이 자동 부여됩니다
Step Functions Workflow Studio를 사용하면 드래그 앤 드롭으로 상태 머신을 시각적으로 설계할 수 있습니다. ASL(Amazon States Language)을 직접 작성하지 않아도 됩니다. 하지만 Retry/Catch 같은 세밀한 설정은 코드 편집기가 더 편리합니다.
Step 3: SQS 큐 생성 및 연동
SQS는 서비스 간 메시지를 안전하게 전달하는 버퍼 역할을 합니다. 처리 결과를 SQS에 넣으면 다른 서비스가 자신의 속도로 소비할 수 있습니다.
- AWS 콘솔에서 SQS 검색 후 클릭
- 대기열 생성 클릭
- 유형: 표준 대기열 선택 (순서보다 처리량이 중요한 경우)
- 이름:
lab-serverless-queue - 구성 섹션에서:
- 가시성 제한 시간: 30초 (메시지를 가져간 후 처리 완료까지 기다리는 시간)
- 메시지 보존 기간: 4일 (처리되지 않은 메시지가 보관되는 기간)
- 배달 지연: 0초 (메시지가 즉시 소비 가능하도록)
- 대기열 생성 클릭
- 생성된 큐의 URL을 복사합니다 (Lambda에서 메시지를 보낼 때 사용)
aws sqs create-queue \
--queue-name lab-serverless-queue \
--attributes VisibilityTimeout=30,MessageRetentionPeriod=345600Step 4: SNS 토픽 연동
SNS는 "발행-구독(Pub/Sub)" 패턴으로 알림을 전송합니다. 한 번 발행하면 이메일, SMS, Lambda 등 여러 구독자에게 동시에 전달됩니다.
- 1AWS 콘솔에서 SNS 검색 후 클릭
- 2토픽 생성 → 유형: 표준 선택
- 3토픽 이름: lab-serverless-notification → 토픽 생성 클릭
- 4토픽 상세 페이지에서 구독 생성 클릭
- 5프로토콜: 이메일 선택, 엔드포인트: 본인 이메일 주소 입력 → 구독 생성 클릭
- 6이메일 받은편지함에서 "AWS Notification - Subscription Confirmation" 메일을 열어 Confirm subscription 링크 클릭
- 7SNS 콘솔에서 구독 상태가 확인됨으로 변경되었는지 확인
- 8메시지 발행 버튼으로 테스트 메시지 전송 → 이메일 수신 확인
Step 5: Lambda Layer 구성
여러 Lambda 함수에서 공통으로 사용하는 유틸리티 코드를 Layer로 분리하면 코드 중복을 줄이고 일괄 업데이트할 수 있습니다.
- 1로컬 터미널에서 공통 유틸리티를 작성합니다: mkdir -p python/lib/python3.12/site-packages # python/lib/python3.12/site-packages/utils.py 파일 작성: # def format_response(status, body): ...
- 2디렉토리를 zip으로 패키징: zip -r layer.zip python/
- 3Lambda 콘솔 → 왼쪽 메뉴 계층 → 계층 생성 클릭
- 4이름: lab-common-utils, 설명: "공통 유틸리티", ZIP 파일 업로드
- 5호환 런타임: Python 3.12 선택 → 생성 클릭
- 6각 Lambda 함수 설정 → 계층 섹션 → 계층 추가 → lab-common-utils 선택
Step 6: Cold Start 테스트
Lambda의 실행 성능을 이해하는 핵심 개념인 Cold Start와 Warm Start를 직접 체험합니다.
- 1Step Functions 콘솔에서 lab-serverless-workflow 선택 → 실행 시작 클릭
- 2입력값: {"name":"테스트","email":"test@example.com","amount":50000} 입력 후 실행
- 3실행 그래프에서 각 단계의 소요 시간을 확인합니다 — 첫 번째 실행이 가장 느립니다 (Cold Start)
- 4CloudWatch Logs에서 각 Lambda의 REPORT 줄을 찾아 Init Duration 값을 확인합니다
- 530초 이내에 동일 실행을 3회 반복합니다 — Init Duration이 사라지는 것을 확인합니다 (Warm Start)
- 65분 이상 대기 후 다시 실행하면 Cold Start가 다시 발생합니다
Cold Start를 줄이는 방법: 1) 함수 패키지 크기 최소화, 2) 전역 범위에서 SDK 클라이언트 초기화, 3) Provisioned Concurrency 설정 (프로덕션 환경). 이 실습에서는 1, 2번을 적용했습니다.
Step 7: 전체 워크플로 통합 테스트
모든 구성 요소가 올바르게 연결되어 동작하는지 체계적으로 검증합니다.
- 1Step Functions 콘솔 → lab-serverless-workflow 선택 → 실행 시작
- 2정상 입력 테스트: {"name":"홍길동","email":"test@example.com","amount":50000}
- 3실행 그래프에서 모든 단계가 초록색(성공) 인지 확인
- 4각 단계를 클릭하여 입력/출력 JSON이 다음 단계로 올바르게 전달되는지 확인
- 5검증 실패 테스트: {"name":"홍길동","email":"test@example.com","amount":-100}
- 6HandleError 상태로 분기되는지 확인
- 7SQS 콘솔에서 lab-serverless-queue 대기열에 메시지가 도착했는지 확인 (메시지 수신 후 확인)
- 8SNS 구독 이메일로 알림이 수신되었는지 확인
Step Functions 실행 상세 페이지에서 이벤트 기록 탭을 열면 각 상태 전환의 타임스탬프, 입력, 출력을 시간순으로 볼 수 있습니다. 디버깅할 때 매우 유용합니다.
트러블슈팅
Step Functions 실행이 "Failed" 상태로 끝나면:
실행 상세에서 어떤 단계에서 실패했는지 확인하세요. 가장 흔한 원인은 ASL 정의에서 ACCOUNT_ID를
실제 계정 ID로 교체하지 않은 것입니다. Lambda ARN이 정확한지 다시 확인하세요.
"States.TaskFailed" 에러가 나오면: 해당 Lambda 함수를 직접 테스트해 보세요. Lambda 콘솔 → 함수 선택 → 테스트 탭에서 Step Functions이 전달하는 것과 동일한 JSON 입력으로 실행합니다.
SNS 이메일이 오지 않으면:
- 스팸함을 확인하세요. 2) 구독 확인 링크를 클릭했는지 확인하세요.
- SNS 콘솔에서 구독 상태가 "확인됨"인지 확인하세요. "보류 중 확인"이면 아직 확인 링크를 클릭하지 않은 것입니다.
Step Functions 실행 역할 관련 에러:
Step Functions이 Lambda를 호출하려면 실행 역할에 lambda:InvokeFunction 권한이 필요합니다.
상태 머신 생성 시 "새 역할 생성"을 선택했다면 자동으로 부여됩니다.
수동으로 역할을 만든 경우 AWSLambdaRole 정책을 연결하세요.
핵심 개념 확인
확장 아이디어
기본 워크플로가 완성되었으니, 더 발전시켜 보세요:
- Parallel 상태 활용: 결제 처리와 재고 확인을 동시에 실행하도록 Parallel 상태 추가
- Choice 상태로 분기: 금액이 10만 원 이상이면 추가 검증 단계를 거치도록 조건 분기
- SQS DLQ 연동: 실패한 메시지를 DLQ(Dead Letter Queue)로 보내고 별도 알림
- DynamoDB에 주문 이력 저장: 각 워크플로 실행 결과를 DynamoDB 테이블에 기록
- Map 상태: 여러 상품을 한 번에 처리하는 반복 실행 패턴 구현
학습 정리
핵심 치트시트
리소스 정리
실습 완료 후 반드시 아래 순서대로 리소스를 정리하여 불필요한 과금을 방지하세요.
- Step Functions 상태 머신 삭제
- Lambda 함수 3개 삭제 (validate, process, notify)
- Lambda Layer 삭제 (
lab-common-utils) - SQS 대기열 삭제 (
lab-serverless-queue) - SNS 토픽 삭제 (
lab-serverless-notification) - API Gateway 삭제 (생성한 경우)
- IAM 역할 정리
- CloudWatch 로그 그룹 삭제