Amazon SAA-C03: 서버리스 및 이벤트 기반 아키텍처 / API 통합 — 학습 가이드
다음의 일부입니다: AWS SAA-C03 — 완벽 학습 가이드. 검증된 답안으로 연습하기: Amazon 시험 허브, 또는 다음에서 시간 제한 모의고사 풀기: ExamRoll.io.
AWS Lambda: 실행 모델, 런타임 수명 주기, 콜드 스타트
Lambda는 두 단계의 수명 주기를 따르는 격리된 Firecracker 마이크로 VM에서 코드를 실행합니다. INIT 단계는 컨테이너를 프로비저닝하고, 런타임을 부트스트랩하며, 배포 패키지를 다운로드하고 압축을 해제한 후, 모듈 수준의 초기화 코드(SDK 클라이언트 생성, KMS로 복호화된 보안 암호 로딩, 데이터베이스 커넥션 풀 설정, JVM 클래스 로딩 및 JIT 웜업 등)를 실행합니다. INVOKE 단계는 핸들러를 실행합니다. 콜드 스타트는 전체 INIT 비용을 발생시키지만, 웜 호출은 환경을 재사용하므로 핸들러 외부에서 캐시된 항목(HTTP keep-alive 풀, 복호화된 보안 암호, DB 클라이언트 등)은 해당 컨테이너에서의 여러 호출에 걸쳐 유지됩니다. 이 때문에 비용이 많이 드는 객체는 모듈 스코프에서 생성하여 재사용하는 것이 표준 패턴입니다.
import boto3, os
ddb = boto3.client('dynamodb') # reused across warm invokes
_secret = None
def _load_secret():
global _secret
if _secret is None:
_secret = kms.decrypt(...) # KMS call once per container, not per invoke
return _secret
def handler(event, ctx):
...
콜드 스타트의 규모는 런타임에 따라 다릅니다. Node.js와 Python은 수십에서 수백 밀리초 수준이지만, JVM과 .NET은 1초를 넘을 수 있습니다. VPC에 연결된 함수의 경우, Hyperplane ENI 덕분에 과거의 ENI 연결 페널티는 대부분 상쇄되었지만, 패키지 크기와 무거운 INIT 코드는 여전히 주요 요인입니다.
콜드 스타트를 해결하는 세 가지 도구는 각기 다른 방식으로 접근합니다.
| 기능 | 동작 방식 | 비용 | 최적 사용 사례 |
|---|---|---|---|
| 온디맨드 동시성 | 기본값. 초기 버스트 약 500–3,000개, 이후 분당 500개씩 확장 | 호출당 + 기간당 과금 | 트래픽이 급증하고, 지연 시간에 민감하지 않은 경우 |
| 프로비저닝된 동시성 | N개의 환경을 미리 초기화하여 트래픽이 도달하기 전에 INIT 완료 | 프로비저닝된 유닛에 대해 24/7 비용 지불 + 호출당 과금 | 엄격한 p99 지연 시간 SLA가 필요한 경우 |
| SnapStart (Java, Python, .NET) | INIT 후 Firecracker 스냅샷 생성. 콜드 스타트 시 복원 | Java는 추가 비용 없음. 다른 런타임은 약간의 캐싱 비용 발생 | 전체 프로비저닝이 낭비인 Java 함수 |
SnapStart는 엄격한 지연 시간 계약이 없는 Java 워크로드에 가장 비용 효율적인 선택지입니다. 호출당 추가 요금 없이 콜드 스타트를 약 10배 줄여줍니다. 프로비저닝된 동시성은 동기식 API가 트래픽 급증 시 p99를 예를 들어 100ms 미만으로 유지해야 할 때 올바른 해답입니다. p95 버스트에 맞춰 크기를 조정하면 꼬리 지연 시간(tail-latency) 문제를 해결할 수 있습니다. 이를 너무 작게 설정하는 것은 전형적인 실패 사례입니다. 온디맨드 방식은 요청이 도착해야만 새 컨테이너를 생성하므로, 트래픽 급증 시 실제 사용자는 수 초간의 대기를 경험하게 됩니다.
# SAM: SnapStart on a Java 17 function
MyJavaFn:
Type: AWS::Serverless::Function
Properties:
Runtime: java17
SnapStart: { ApplyOn: PublishedVersions }
AutoPublishAlias: live
프로비저닝된 동시성 자체도 Application Auto Scaling을 통해 확장할 수 있습니다. 예약된 작업을 통해 07:45에 10개에서 200개로 늘리고 10:00에 다시 줄이면, 밤사이 웜 상태의 용량에 대한 비용을 지불하지 않으면서 아침 트래픽 급증으로 인한 콜드 스타트를 제거할 수 있습니다.
메모리 크기 설정은 동시에 CPU를 조절하는 다이얼이기도 합니다. vCPU는 vCPU당 약 1,769MB까지 메모리에 비례하여 선형적으로 확장됩니다. 128MB로 고정된 함수가 1,024MB 함수보다 전체 비용이 더 많이 나올 수 있는데, 이는 실행 시간이 두 배 이상 늘어나는 것이 ms당 가격이 두 배가 되는 것보다 비용에 더 큰 영향을 미치기 때문입니다. 추측하지 마십시오. AWS Lambda Power Tuning을 사용하여 대표적인 페이로드를 대상으로 여러 구성을 테스트해야 합니다.
Lambda 동시성 제어 및 다운스트림 시스템 보호
세 가지 동시성 다이얼이 중요하며, 각각 다른 역할을 합니다.
- **예약된 동시성(Reserved concurrency)**은 함수가 사용할 수 있는 동시 실행의 수를 제한하고 예약합니다. 계정 풀에서 용량을 할당받아 다운스트림 시스템(작은 RDS 인스턴스, 속도 제한이 있는 파트너 API 등)이 과부하되는 것을 방지합니다.
- **프로비저닝된 동시성(Provisioned concurrency)**은 환경을 미리 초기화합니다. 이는 확장 레버가 아닌 지연 시간 레버입니다.
- **예약되지 않은 계정 동시성(Unreserved account concurrency)**은 공유 풀이며, 리전당 기본값은 1,000입니다.
Lambda가 “무한히 확장된다"고 가정하는 것은 두 가지 상한선을 간과하는 것입니다. 첫째, 계정 수준의 동시 실행 제한은 실재하며, 버스트 한도(리전에 따라 초기 500–3,000, 이후 분당 +500)가 확장 속도를 제어합니다. 이 한도를 초과하면 동기식 호출자는 429 TooManyRequestsException을 받게 되며, 이는 API Gateway에서 5xx 오류로 나타납니다. 둘째, 다운스트림 시스템에도 자체적인 한계가 있습니다. max_connections=85로 설정된 db.t3.micro 인스턴스는 각각 커넥션을 여는 1,000개의 동시 Lambda 실행을 감당할 수 없습니다. PostgreSQL은 커넥션당 백엔드 프로세스를 포크(fork)하며 약 10MB의 RAM을 소비합니다. CPU 여유가 있더라도 커넥션 설정 및 해제만으로 인스턴스 리소스를 고갈시킬 수 있습니다.
두 가지 완화책은 (1) 다수의 클라이언트 측 커넥션을 풀링하여 소수의 영구적인 백엔드 커넥션으로 멀티플렉싱하는 RDS Proxy를 사용하거나, (2) 큐를 삽입하여 처리 속도를 도착 속도와 분리하는 것입니다.
import psycopg2, os
conn = psycopg2.connect(
host=os.environ['PROXY_ENDPOINT'], # RDS Proxy, not the DB directly
dbname='orders', user='app', password=get_secret())
RDS Proxy는 드라이버와 연결 문자열이 거의 변경되지 않는 최소 변경 솔루션이므로, “애플리케이션 변경 최소화"와 커넥션 고갈 문제 해결이 요구사항일 때 올바른 해답입니다. DynamoDB는 이런 문제가 없습니다. HTTPS API가 상태 비저장(stateless) 방식이기 때문에, DynamoDB는 팬아웃(fan-out)이 큰 Lambda 워크로드와 자연스럽게 어울립니다.
Lambda IAM, 환경 변수, 그리고 네트워킹
모든 함수는 호출 시 **실행 역할(execution role)**을 맡습니다. 이 역할의 신뢰 정책은 lambda.amazonaws.com에 sts:AssumeRole을 허용하고, 권한 정책은 함수가 수행할 수 있는 작업을 정의합니다. 런타임은 수명이 짧은 STS 자격 증명을 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN에 자동으로 주입합니다. IAM 사용자 액세스 키를 환경 변수나 코드에 포함시키지 마십시오. 이 키들은 정적이며, 유출된 소스 코드나 CloudTrail export에서 발견될 수 있고, 수동으로 교체해야 하며, 임시 자격 증명 모델 전체를 우회하게 됩니다.
FnRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal: { Service: lambda.amazonaws.com }
Action: sts:AssumeRole
Policies:
- PolicyName: ReadOrders
PolicyDocument:
Statement:
- Effect: Allow
Action: ["dynamodb:GetItem", "dynamodb:Query"]
Resource: !GetAtt OrdersTable.Arn
민감한 구성을 담고 있는 환경 변수는 고객 관리형 KMS 키로 암호화해야 하며, 콘솔이 클라이언트 측에서 암호화하도록 “전송 중 암호화를 위한 헬퍼"를 사용해야 합니다. INIT 단계에서 한 번만 복호화하고 평문(plaintext)을 모듈 수준 변수에 캐시하십시오. 그렇지 않으면 모든 호출마다 KMS API 호출 비용을 지불하게 됩니다.
기본적으로 함수는 AWS 관리형 VPC에서 실행되며 아웃바운드 인터넷 접근에 제한이 없습니다. 함수를 자체 VPC에 연결하는 것은 VPC 내 리소스(프라이빗 서브넷의 RDS, ElastiCache, Direct Connect를 통한 온프레미스 등)에 접근해야 할 때만 해당됩니다. 그러면 Lambda는 지정한 서브넷에 Hyperplane ENI를 연결하고 해당 서브넷의 라우팅을 상속받습니다.
전형적인 함정은 Lambda를 프라이빗 서브넷에 배치하고 AWS 서비스 트래픽을 위한 경로를 NAT 게이트웨이 또는 더 나쁘게는 직접 관리하는 NAT 인스턴스를 통해서만 허용하는 것입니다. NAT 인스턴스는 단일 NIC에서 포화 상태가 되고, SPOF(단일 장애점)이며, GB당 요금이 청구됩니다. NAT 게이트웨이조차도 GB당 요금이 부과되며 AWS 서비스 트래픽에는 불필요합니다. 올바른 패턴은 다음과 같습니다.
- S3와 DynamoDB를 위한 게이트웨이 VPC 엔드포인트 (무료)
- KMS, Secrets Manager, SQS, SNS, STS 및 유사 서비스를 위한 인터페이스(PrivateLink) 엔드포인트
이렇게 하면 트래픽이 AWS 백본에 머무르게 되어 NAT 처리량 상한을 없애고 예상치 못한 egress 요금을 방지할 수 있습니다. Lambda ENI는 절대 퍼블릭 IP를 받지 않는다는 점에 유의하십시오. 함수를 “퍼블릭” 서브넷에 배치해도 인터넷에 접근할 수 없으며, 적절한 라우팅이 설정된 별도의 퍼블릭 서브넷에 있는 NAT 게이트웨이가 여전히 필요합니다.
Amazon API Gateway: 엔드포인트 유형, 인증, 그리고 전송
API Gateway는 세 가지 API 유형을 제공합니다.
| 기능 | REST API | HTTP API | WebSocket |
|---|---|---|---|
| 지연 시간 | 더 높음 | 약 60% 더 낮음 | 상태 유지, 양방향 |
| 비용 | 더 높음 | 약 70% 더 저렴 | 메시지당 |
| 사용량 계획 / API 키 | 예 | 아니요 | 아니요 |
| 요청/응답 변환(VTL) | 예 | 제한적 | — |
| JWT 권한 부여자 | Lambda를 통해 | 네이티브 | Lambda를 통해 |
| WAF | 예 | 아니요 (CloudFront로 앞단에 배치) | 예 |
API 키와 사용량 계획, JSON Schema 요청 유효성 검사, VTL 매핑 템플릿, 메서드별 스코프를 가진 Cognito 권한 부여자, 또는 WAF가 필요할 때는 REST를 선택하고, 비용과 지연 시간이 더 중요한 경량 JWT 인증 프록시 패턴에는 HTTP를 선택하십시오.
엔드포인트 유형은 API가 어디에 위치하는지를 결정합니다.
- 엣지 최적화(Edge-optimized): Gateway가 관리하는 CloudFront 배포를 통해 제공되며, TLS는 가장 가까운 POP에서 종료됩니다. 전 세계에 분산된 클라이언트에 가장 적합합니다.
- 리전(Regional): CloudFront 없이 단일 리전에서 노출됩니다. 클라이언트가 동일 리전에 있거나, 자체 CloudFront를 앞에 두거나, 여러 리전에 걸쳐 Route 53 지연 시간 기반 라우팅을 사용할 때 가장 적합합니다.
- 프라이빗(Private): 인터페이스 VPC 엔드포인트를 통해서만 접근 가능합니다. 공용 인터넷을 거치면 안 되는 내부 마이크로서비스에 가장 적합합니다.
내부용 단일 리전 API에 엣지 최적화를 선택하면 불필요한 CloudFront 홉이 추가되고 배포 전파가 느려집니다. 전 세계적으로 사용되는 퍼블릭 API에 리전을 선택하면 모든 요청이 공용 인터넷을 거쳐 하나의 리전으로 향하게 됩니다.
사용자 지정 도메인은 엔드포인트 유형에 따라 위치가 다른 ACM 인증서를 필요로 합니다. 엣지 최적화의 경우 us-east-1(CloudFront는 글로벌 서비스이며 여기서 TLS를 종료함), 리전 엔드포인트의 경우 API 자체 리전입니다. 이를 혼동하는 것은 흔한 구성 오류입니다. 기본 경로 매핑을 사용하면 하나의 도메인으로 여러 API를 다중화할 수 있습니다 (/orders → orders API, /users → users API).
인증에는 네 가지 모델이 있으며, 내장 기능을 사용하지 않고 다른 방법을 찾는 것은 전형적인 안티패턴입니다.
| 메커니즘 | 사용 시기 |
|---|---|
| IAM 인증 | 호출자가 SigV4에 서명할 수 있는 AWS 보안 주체일 때 (다른 서비스, SDK, 교차 계정) |
| Cognito 사용자 풀 권한 부여자 | 사용자가 Cognito 사용자 풀에 대해 인증하고, Gateway가 JWT를 검증할 때 |
| Lambda 권한 부여자 | 비표준 토큰, OIDC를 지원하지 않는 서드파티 IdP, 요청별 복잡한 로직이 필요할 때 |
| API 키 + 사용량 계획 | 사용량 측정, 스로틀링, 할당량 — 절대 인증 수단으로 사용하지 않음 |
사용자 지정 Lambda 권한 부여자는 요청당(또는 캐시 TTL당) 추가적인 호출을 발생시키고, 패치 및 모니터링해야 할 함수가 하나 더 늘어나며, 서명 검증 버그가 조용히 접근을 허용할 수 있는 코드 경로를 만듭니다. 내장 기능으로 요구사항을 정말로 표현할 수 없을 때만 사용하십시오.
Lambda 프록시 통합은 기본 패턴입니다. 전체 요청이 이벤트로 전달되고 함수는 다음과 같은 응답 봉투(envelope) 형태를 반환해야 합니다.
{
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": "{\"orderId\":\"abc123\"}",
"isBase64Encoded": false
}
매우 높은 TPS로 fire-and-forget 방식의 수집을 할 경우, Gateway의 직접 AWS 서비스 통합을 사용하여 Lambda 홉을 완전히 건너뛰고 SQS나 Kinesis로 바로 푸시하십시오. 이는 쓰기 경로에서의 콜드 스타트를 제거하고 수집 속도와 처리 용량을 분리(디커플링)합니다.
안전한 롤아웃을 위해 스테이지에서 카나리 배포를 사용하십시오. 트래픽의 일부 비율이 새 배포로 전달되는 동안 대부분은 안정적인 버전에 머무르며, 카나리별 CloudWatch 지표를 통해 승격 또는 롤백을 결정합니다.
aws apigateway update-stage --rest-api-id abc123 --stage-name prod \
--patch-operations \
op=replace,path=/canarySettings/percentTraffic,value=10 \
op=replace,path=/canarySettings/deploymentId,value=xyz789
API Gateway의 복잡한 절차가 과도한 간단한 웹훅(단일 테넌트 Slack 콜백, GitHub 푸시 핸들러 등)의 경우, Lambda 함수 URL을 사용하면 함수에 직접 전용 HTTPS 엔드포인트를 제공할 수 있습니다. 호출자가 AWS 보안 주체일 때는 AuthType: AWS_IAM으로 보안을 설정하십시오. NONE인 경우, 함수 내에서 요청 서명을 반드시 검증해야 합니다. AuthType: NONE이고 함수 내 검증이 없는 함수 URL은 공용 인터넷에 노출된 익명의 컴퓨팅 엔드포인트입니다.
호출 유형, 재시도 및 멱등성
이벤트 소스는 동작 방식이 매우 다른 두 가지 범주로 나뉩니다. 푸시 기반 소스(API Gateway, ALB, S3, SNS, EventBridge, Cognito)는 Lambda를 직접 호출하며, lambda:InvokeFunction 권한을 부여하는 AWS::Lambda::Permission 리소스 기반 정책이 필요합니다. 이 정책에는 올바른 Principal(예: events.amazonaws.com)과 SourceArn이 명시되어야 합니다. 이 정책이 없으면 규칙이 이벤트와 일치하더라도 모든 호출이 조용히 거부됩니다. 즉, 함수는 전혀 실행되지 않으며 실패는 CloudTrail에서만 확인할 수 있습니다. 이는 함수가 무엇을 할 수 있는지를 제어하는 실행 역할과는 별개의 개념입니다. 실행 역할은 누가 함수를 호출할 수 있는지가 아니라, 호출된 함수가 어떤 작업을 수행할 수 있는지를 관장합니다.
폴링 기반 소스(SQS, Kinesis, DynamoDB Streams, MSK)는 Lambda 서비스가 이벤트 소스 매핑을 통해 읽어 들입니다. 따라서 리소스 기반 정책은 필요 없지만, 실행 역할에 읽기 권한이 반드시 부여되어야 합니다.
호출 유형에 따라 재시도 동작 방식이 달라집니다.
- 동기식 (API Gateway, ALB,
RequestResponseSDK): 오류가 즉시 반환되며, 재시도 책임은 호출자에게 있습니다. - 비동기식 (S3, SNS, EventBridge): Lambda가 내부 큐에 이벤트를 버퍼링하고, 실패 시 지연을 두고 두 번 재시도한 후 DLQ 또는 실패 시 대상으로 보냅니다.
- SQS 이벤트 소스 매핑: SQS는
maxReceiveCount에 도달하여 소스 큐의 DLQ로 이동할 때까지 메시지를 계속 재전송합니다. - Kinesis / DynamoDB Streams: 성공하거나 만료될 때까지 단일 샤드 배치를 재시도하며, 그동안 해당 샤드를 블로킹합니다. 처리되지 못하는 배치가 해당 파티션의 모든 다운스트림 처리를 지연시킬 수 있습니다.
모든 계층에 재시도 로직이 내장되어 있으므로, 멱등성(idempotency)은 선택이 아닌 필수입니다. 느린 쓰기 작업 중에 SQS 가시성 제한 시간이 만료되거나, 다운스트림에서 5xx 오류가 발생한 후 비동기 재시도가 일어나는 경우 중복이 발생할 수 있습니다. 표준적인 패턴은 결정적 키(deterministic key)와 DynamoDB 조건부 쓰기를 사용하는 것입니다.
def handler(event, context):
msg_id = event['Records'][0]['messageId']
try:
ddb.put_item(
TableName='processed',
Item={'id': {'S': msg_id}, 'ttl': {'N': str(ttl)}},
ConditionExpression='attribute_not_exists(id)')
except ddb.exceptions.ConditionalCheckFailedException:
return # already processed
process(event)
AWS Lambda Powertools의 @idempotent 데코레이터는 DynamoDB를 백엔드로 사용하여 바로 이 패턴을 구현합니다.
SQS와 SNS를 이용한 디커플링
팬아웃(fan-out)이 많은 푸시 소스를 Lambda에 직접 연결하는 것은 취약합니다. 예를 들어, S3 이벤트 알림은 이벤트별로 동기식으로 처리되며 Lambda의 동시성 한도에 영향을 받습니다. 대량의 업로드(예: 마케팅 캠페인으로 수천 개의 문서가 몇 초 만에 업로드되는 경우) 중에 사용 가능한 동시성을 초과하는 호출이 발생하면, S3의 재시도 창이 짧아 이벤트가 사실상 유실될 수 있습니다. 해결책은 버퍼를 사용하는 것입니다.
| 패턴 | 사용 시점 |
|---|---|
| S3 → Lambda 직접 연결 | 이벤트 발생률이 낮고 예측 가능할 때, 멱등성 처리가 가능할 때 |
| S3 → SQS → Lambda | 워크로드가 폭주(bursty)할 때, 재시도/DLQ가 필요할 때, 다운스트림 처리율 제한이 필요할 때 |
| S3 → SNS → 다중 SQS | 여러 독립적인 소비자에게 팬아웃할 때 |
| S3 → EventBridge → 다수 대상 | 계정 간 라우팅, 콘텐츠 기반 필터링이 필요할 때 |
SNS는 발행/구독(pub/sub) 모델입니다. 한 번의 발행으로 여러 구독자(SQS, Lambda, HTTPS, 이메일 등)에게 메시지를 전달합니다. 메시지 필터링은 속성(attribute) 기반입니다. SQS는 메시지를 최대 14일까지 보관하는 내구성 있는 포인트-투-포인트 큐입니다. 가장 일반적이면서도 강력한 조합은 SNS → SQS 팬아웃 구성으로, 각 소비자에게 독립적인 스케일링과 재처리를 위한 자체 버퍼 큐를 제공합니다.
엄격한 순서 보장이 필요한 경우(예: 고객별 주문을 순차적으로 처리), MessageGroupId를 순서 지정 키로 설정한 SQS FIFO 큐를 사용하세요. 동일한 그룹 내의 메시지들은 순서대로 전달되며, 다른 그룹들은 병렬로 처리됩니다. 표준 SQS는 최선 노력(best-effort) 순서 보장만 제공합니다.
표준적인 디커플링된 수집 패턴은 API Gateway의 SQS 직접 통합을 사용하여 갑작스러운 트래픽 폭증을 흡수하고, 처리율이 제한된 프로세서로 처리하는 것입니다.
Resources:
OrdersQueue:
Type: AWS::SQS::Queue
Properties:
FifoQueue: true
ContentBasedDeduplication: true
RedrivePolicy:
deadLetterTargetArn: !GetAtt OrdersDLQ.Arn
maxReceiveCount: 5
ProcessorFunction:
Type: AWS::Lambda::Function
Properties:
ReservedConcurrentExecutions: 20 # cap the DB write rate
Mapping:
Type: AWS::Lambda::EventSourceMapping
Properties:
EventSourceArn: !GetAtt OrdersQueue.Arn
FunctionName: !Ref ProcessorFunction
BatchSize: 10
예약된 동시성을 설정하는 것은 의도적인 조치입니다. 이는 데이터베이스에 가해지는 쓰기 속도를 제한하여, RDS가 아닌 큐가 트래픽 폭증을 흡수하도록 만듭니다. 실패한 메시지는 maxReceiveCount에 도달한 후 오프라인 분석을 위해 DLQ로 라우팅됩니다.
EventBridge: 규칙, 입력 변환 및 API 대상
EventBridge는 스키마를 인지하는 이벤트 버스로, 풍부한 JSON 패턴 매칭, SaaS 파트너 소스, 스키마 레지스트리, 아카이브/재생 기능을 제공합니다. 규칙은 이벤트 패턴과 일치하는 이벤트를 30개 이상의 대상 유형(Lambda, Step Functions, SQS, Kinesis, ECS, Firehose 등)으로 팬아웃하며, SNS처럼 속성뿐만 아니라 메시지 본문의 콘텐츠 기반 필터링도 가능합니다.
{
"source": ["tenant.energy"],
"detail-type": ["UsageReported"],
"detail": { "kWh": [{ "numeric": [">", 100] }] }
}
하나의 규칙은 최대 5개의 대상을 가질 수 있으며, 각 대상은 원본 이벤트를 그대로 받거나 변환된 일부만 받을 수 있습니다. **입력 변환기(Input transformers)**는 느슨한 결합(loose coupling)을 강제합니다. InputPathsMap은 이벤트에서 JSON 경로를 추출하고, InputTemplate은 이를 대상이 기대하는 형식으로 정확하게 재구성합니다.
EventPattern:
source: ["com.acme.orders"]
detail-type: ["OrderPlaced"]
Targets:
- Arn: !GetAtt PaymentValidator.Arn
InputTransformer:
InputPathsMap:
orderId: "$.detail.orderId"
amount: "$.detail.total"
card: "$.detail.payment.cardToken"
InputTemplate: |
{"orderId": <orderId>, "amount": <amount>, "cardToken": <card>}
각 검증 Lambda는 필요한 데이터만 수신합니다. 주소 검증기는 카드 토큰을 볼 일이 없습니다. 이는 전체 이벤트를 받아 내부적으로 분기 처리하는 단일(monolithic) Lambda보다 훨씬 뛰어난 방식입니다. 단일 Lambda는 IAM 권한을 한곳에 집중시키고(하나의 역할이 모든 다운스트림 권한을 가져야 함), 버그의 장애 영향 반경을 넓히며, 배포 주기를 종속시키고, 책임별 메모리/타임아웃 튜닝을 불가능하게 하며, 가장 빈번한 분기의 처리율에 맞춰 전체 함수를 확장하도록 강제합니다.
**API 대상(API destinations)**은 반대 방향으로 작동합니다. EventBridge가 외부 HTTPS 엔드포인트를 호출합니다. Secrets Manager에 Basic, API 키 또는 OAuth 자격 증명을 저장하는 **연결(connection)**과 함께 사용하면, 예를 들어 AWS Batch 작업이 성공했을 때 Lambda 없이도 서드파티 SaaS에 알림을 보내는 서버리스 방식이 됩니다. EventBridge가 상태 변경 이벤트를 캡처하고, 규칙이 JobSucceeded와 일치하면, API 대상이 연결에서 주입된 자격 증명으로 해당 벤더에 POST 요청을 보냅니다.
예약된 규칙(cron/rate 표현식) 또는 더 새로운 EventBridge Scheduler는 야간 리포트 생성, 매시간 캐시 새로 고침과 같은 주기적인 작업을 위해 하트비트 EC2 인스턴스를 대체합니다.
메시지 본문 콘텐츠(단순 속성 아님)에 대한 필터링이 필요하거나, 생산자 변경 없이 나중에 새로운 소비자를 연결해야 하거나, 라우팅이 여러 계정이나 SaaS 소스에 걸쳐 있을 때는 SNS보다 EventBridge를 선택하세요. 팬아웃이 안정적인 구독자 집합에 대한 단순한 속성 기반 알림일 경우에는 SNS를 선택하는 것이 좋습니다.
Step Functions: 오케스트레이션 및 분산 맵
워크플로우에 몇 개 이상의 단계, 분기, 재시도, 사람의 승인 또는 긴 대기 시간이 포함될 때, 이러한 로직을 연쇄적인 Lambda 함수에 내장하면 유지 관리가 불가능해집니다. Step Functions는 Amazon States Language를 사용하여 상태 머신을 외부화합니다.
- 표준 워크플로우(Standard workflows): 최대 1년, 정확히 한 번(exactly-once) 시맨틱, 전체 실행 기록, 사람/외부 게이트를 위한
.waitForTaskToken지원. 주문 처리, ETL, 승인 플로우 등에 사용됩니다. - Express 워크플로우(Express workflows): 최대 5분, 최소 한 번(at-least-once) 시맨틱, 높은 볼륨, 실행당 저렴한 비용. API Gateway 뒤의 짧은 동기식 오케스트레이션, IoT 및 스트리밍 변환에 사용됩니다.
모든 태스크는 명시적인 Retry와 Catch를 선언해야 합니다:
"ValidatePayment": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {"FunctionName": "PaymentValidator", "Payload.$": "$"},
"Retry": [{
"ErrorEquals": ["Lambda.ServiceException", "Lambda.TooManyRequestsException"],
"IntervalSeconds": 2, "MaxAttempts": 4, "BackoffRate": 2.0
}],
"Catch": [{"ErrorEquals": ["PaymentDeclined"], "Next": "RefundStep"}],
"Next": "ShipOrder"
}
Parallel 및 Map 상태는 분기를 동시에 실행하고 결과를 집계합니다. 이는 주소, 인벤토리, 결제 등 독립적인 검증기가 있는 주문 시스템에 깔끔하게 들어맞습니다. 단계 간의 상태는 실행의 JSON 문서를 통해 전달되므로, 워크플로우 조정을 위해서만 사용되는 공유 데이터베이스가 필요 없습니다.
.waitForTaskToken 패턴은 외부 액터가 토큰과 함께 SendTaskSuccess를 호출할 때까지 실행을 일시 중지합니다. 이는 워크플로우가 Lambda, EC2, 컨테이너, 온프레미스 시스템에 걸쳐 있고 최소한의 운영 오버헤드로 수동 승인이 필요할 때 표준적인 해답입니다.
"ManagerApproval": {
"Type": "Task",
"Resource": "arn:aws:states:::sns:publish.waitForTaskToken",
"Parameters": {
"TopicArn": "arn:aws:sns:us-east-1:111:approvals",
"Message": { "TaskToken.$": "$$.Task.Token", "OrderId.$": "$.orderId" }
},
"Next": "Fulfill"
}
Distributed Map은 표준 Map 상태를 확장하여 최대 10,000개의 병렬 하위 실행을 처리할 수 있으며, S3 버킷의 객체나 CSV/JSONL 파일의 행을 직접 반복 처리할 수 있습니다. 자동 배치, 체크포인팅, 장애 허용 기능이 내장되어 있습니다. 수천 개의 반정형 S3 객체의 경우, 운영상 가장 효율적인 옵션입니다. 프리픽스를 지정하고, 항목별 태스크를 정의하면 Step Functions가 팬아웃, MaxConcurrency, 재시도, 결과 집계를 처리합니다.
{
"Type": "Map",
"ItemReader": {
"Resource": "arn:aws:states:::s3:listObjectsV2",
"Parameters": { "Bucket": "raw-events", "Prefix": "2024/" }
},
"MaxConcurrency": 1000,
"ItemProcessor": {
"ProcessorConfig": { "Mode": "DISTRIBUTED", "ExecutionType": "STANDARD" },
"StartAt": "ProcessObject",
"States": { "ProcessObject": { "Type": "Task", "Resource": "arn:aws:lambda:...:function:ProcessOne", "End": true } }
}
}
SQS나 EventBridge에서 동일한 기능을 재구축하려면 완료, 재시도, 결과 취합을 위한 커스텀 북키핑(bookkeeping)이 필요합니다.
Step Functions vs. EventBridge: Step Functions는 상태, 분기, 재시도, 승인 등 사용자가 순서와 결과를 소유해야 할 때 적합합니다. EventBridge는 생산자가 소비자가 누구인지 모르거나 신경 쓰지 않고, 소비자가 독립적으로 연결될 때 적합합니다.
S3 이벤트 알림
업로드의 거의 실시간 처리를 위해, s3:ObjectCreated:*(또는 Put, Post, CompleteMultipartUpload와 같은 특정 변형)에 대해 S3 이벤트 알림을 Lambda 대상으로 구성합니다. 단, 위에서 언급한 버스트(burst) 주의 사항이 적용됩니다. 가드레일:
- 다운스트림 데이터베이스를 보호하기 위해 **예약된 동시성(reserved concurrency)**을 설정합니다.
- 포이즌 메시지를 위해 **DLQ 또는 실패 시 대상(on-failure destination)**을 활성화합니다.
- 여러 소비자가 동일한 이벤트를 필요로 할 때 S3 이벤트를 EventBridge를 통해 라우팅합니다. 직접적인 S3 알림 구성은 개수와 표현력에 한계가 있습니다. EventBridge의 팬아웃과 대상별 입력 변환기(input transformer)를 사용하면 훨씬 더 잘 확장됩니다.
스트리밍: Kinesis Data Streams vs. Firehose
**Kinesis Data Streams (KDS)**는 샤딩되고, 순서가 있으며, 재생 가능한 로그로 24시간에서 365일까지 데이터를 보존합니다. 순서는 파티션 키를 기준으로 샤드별로 보장됩니다. 이는 디바이스별 또는 테넌트별 집계에 매우 중요합니다. 여러 소비자가 독립적으로 읽을 수 있습니다(소비자별 격리된 처리량을 위한 향상된 팬아웃). 순서 있는 재생, 여러 독립적인 소비자, 또는 샤드당 높은 처리량이 필요할 때 KDS를 선택합니다.
Kinesis Data Firehose는 S3, Redshift, OpenSearch 또는 Splunk로 데이터를 전송하는 완전 관리형 스트림입니다. 버퍼링(60초 또는 1–128MB), 선택적 Lambda 변환, 압축(GZIP, Snappy), Parquet/ORC 변환 기능이 내장되어 있습니다. 관리할 샤드가 없습니다. 커스텀 소비자나 재생 기능이 필요 없고 거의 실시간으로 데이터를 저장하기만 하면 될 때 Firehose는 운영 부담이 적은 선택입니다.
표준적인 거의 실시간 분석 파이프라인은 생산자 → KDS → Firehose → S3 (Parquet) → Athena/QuickSight이며, Firehose에서 선택적으로 Lambda 보강(enrichment)을 추가할 수 있습니다.
관리형 SFTP를 위한 AWS Transfer Family
파트너가 S3 또는 EFS로/에서 SFTP, FTPS, 또는 FTP를 요구할 때, AWS Transfer Family는 클라이언트가 이미 사용하는 프로토콜을 지원하는 관리형 다중 AZ 엔드포인트를 제공합니다. 인증은 서비스 관리형 사용자, SSH 키, 또는 API Gateway/Lambda를 통한 커스텀 IdP를 지원합니다. 파일은 SSE 및 수명 주기 정책이 적용된 상태로 S3에 직접 저장됩니다. IAM 범위 축소 정책(scope-down policy)은 각 사용자를 특정 프리픽스로 제한합니다.
EC2에서 이를 직접 구축하려면 OpenSSH 강화, 패치, AZ 간 HA, 키 순환, 로그 전달이 필요하며, Transfer Family는 이 모든 것을 대신 처리합니다. ‘파트너가 SFTP를 통해 파일을 보낸다’는 요구사항이 있고 최소한의 운영 오버헤드로 파일을 S3에 저장하고 싶을 때마다 이 서비스를 선택합니다.
표준 서버리스 패턴 구성하기
테넌트별 시간당 지표를 위한 저부하 수집 설계: 센서가 **API Gateway (HTTP API, 리전별)**로 POST → Lambda가 검증 후 EventBridge에 게시 → 규칙이 DynamoDB 작성기 Lambda(파티션 키로 테넌트 ID, 정렬 키로 시간 버킷)로 라우팅 하고, 병렬로 분석을 위해 **Firehose → S3 (Parquet)**로 라우팅합니다. 새로운 소비자는 생산자를 건드리지 않고 추가적인 EventBridge 규칙으로 연결됩니다. 이는 SNS만으로는 깔끔하게 충족할 수 없는 확장성 요구사항입니다. 지속적인 처리량과 순서가 중요한 경우(결제 조정, 금융 이벤트 스트림), EventBridge를 Kinesis Data Streams로 교체하고 독립적인 소비자를 위해 향상된 팬아웃을 사용합니다.
함정 카탈로그: 흔한 안티패턴이 실패하는 이유
프라이빗 서브넷 람다에서 AWS 서비스로 향하는 트래픽에 NAT 인스턴스/게이트웨이 사용. NAT 인스턴스는 처리량을 단일 EC2 NIC에 종속시키며 단일 장애점(SPOF)이 됩니다. NAT 게이트웨이는 GB당 요금이 부과됩니다. AWS 서비스가 목적지인 경우 이 둘은 모두 불필요합니다. S3/DynamoDB에는 게이트웨이 엔드포인트를, 그 외 모든 서비스에는 인터페이스 엔드포인트를 사용하세요.
지연 시간에 민감한 API에서 콜드 스타트 무시. 온디맨드 방식은 요청이 도착했을 때만 컨테이너를 프로비저닝하므로, 트래픽 폭증(burst) 시 SLA를 위반할 수 있습니다. p95 수준의 폭증 트래픽에 맞춰 프로비저닝된 동시성을 설정하고, 엄격한 SLA가 없는 Java 워크로드에는 SnapStart를 사용하세요.
전체 이벤트를 받아 내부적으로 분기하는 모놀리식 람다. 최소 권한 원칙을 위반하고(하나의 역할이 모든 다운스트림 권한을 가짐), 배포 주기를 종속시키며, 책임별 튜닝을 방해하고, 가장 빈번하게 호출되는 분기의 비율에 맞춰 전체 함수를 확장시킵니다. 책임에 따라 함수를 분리하고 EventBridge나 Step Functions로 연결하세요.
다수 람다에서 직접 DB에 연결. 컨테이너는 커넥션 풀을 공유하지 않으므로 총 연결 수는 동시 호출 수와 같아집니다. RDS Proxy(풀링), 예약된 동시성(호출률 제한), 또는 SQS(버퍼링)로 해결하세요.
폭증(burst)하는 데이터 수집에 동기식 람다 사용. 동시성 한도를 초과하면 API Gateway에는 429, 클라이언트에는 5xx 오류가 반환됩니다. 트래픽 폭증 시 S3 직접 알림은 이벤트를 조용히 유실시킵니다. SQS를 중간에 추가하거나, Gateway → SQS 직접 통합을 사용하세요.
AuthType: NONE으로 설정하고 함수 내 시그니처 검증이 없는 퍼블릭 람다 함수 URL. 공개 인터넷에 노출된 익명 컴퓨팅 리소스가 됩니다. AWS 호출자는 AWS_IAM을 사용하고, 서드파티 웹훅은 시그니처를 검증하도록 하세요.
내장 기능으로 충분한데 커스텀 람다 권한 부여자(authorizer) 사용. 지연 시간을 추가하고, 패치가 필요한 함수를 하나 더 늘리며, 시그니처 검사 버그가 발생 시 조용히 액세스를 허용하는 코드 경로를 만듭니다. AWS 보안 주체(principal)에는 IAM 권한 부여를, 사용자 풀에는 Cognito 권한 부여자를 사용하는 것이 좋습니다.
커스텀 도메인에 잘못된 리전의 ACM 인증서 사용. 엣지 최적화 엔드포인트는 us-east-1 리전의 인증서가 필요하고, 리전 엔드포인트는 API와 동일한 리전의 인증서가 필요합니다.
푸시 소스(EventBridge, S3, SNS)에 대한 AWS::Lambda::Permission 누락. 이벤트가 규칙과 일치하더라도 호출이 조용히 거부됩니다. 이는 실행 역할과는 다릅니다. 이 권한은 함수가 무엇을 할 수 있는지가 아니라, 누가 함수를 호출할 수 있는지를 제어합니다.
멱등성 처리 누락. 비동기 호출, 가시성 시간 초과 만료 시 SQS 재전송, Kinesis 배치 재시도 등 모든 계층에서 재시도가 발생합니다. 결정론적인 중복 제거 키와 조건부 쓰기 없이는 중복 데이터 처리가 불가피합니다.
← 컨테이너 및 오케스트레이션 · 모든 도메인 · 스토리지 및 데이터 수명 주기 →
이 문제 연습하기 → · ExamRoll.io에서 시간 제한 연습 →
Pass the whole exam — not just this question
You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.
시험 합격하기 →