AWS 고급 #5 EventBridge / SQS / SNS
#3 Lambda, #4 API Gateway가 동기 호출의 영역이었다면, 이번엔 비동기 / 이벤트 주도 방식입니다. 호출자가 결과를 기다리지 않고, 컴포넌트 사이가 메시지로 느슨하게 연결되는 패턴입니다.
AWS에는 이 영역의 도구가 셋, SNS / SQS / EventBridge. 비슷해 보이지만 강조점이 다릅니다. 이 글에서 그 차이를 정확히 나누고, fan-out 패턴, DLQ, 멱등성 같은 운영 포인트까지 한 번에 정리합니다.
셋의 차이: 한 줄 비교 #
| SNS | SQS | EventBridge | |
|---|---|---|---|
| 모델 | Pub/Sub (push) | Queue (pull) | Event Bus (push, 라우팅 룰) |
| 받는 쪽 | 0~N 구독자 동시 | 1 명만 (한 메시지에) | 0~N (rule 매칭에 따라) |
| 보존 | 즉시 push, 안 받으면 사라짐 | 최대 14일 큐에 보관 | rule 매칭 즉시 push |
| 적합한 경우 | 한 이벤트 → 여러 받는 쪽 | 작업 큐, 백프레셔 | 이벤트 기반 라우팅 (다중 소스) |
| 통합 | Lambda, SQS, HTTP, Email, SMS | Lambda, ECS, EC2 (폴링) | Lambda, SQS, SNS, ECS, Step Functions, … 25+ |
가장 자주 보는 패턴 한 줄로:
┌──────────────┐
│ │
생산자 ─→ SNS ─→ ├─→ SQS ─→ Lambda
└─→ Lambda Worker (긴 처리)
(한 이벤트) (즉시 push)
생산자 ─→ EventBridge ──┬─→ Lambda (룰 A 매칭)
(다양한 소스) ├─→ Step Functions (룰 B)
└─→ SQS (룰 C)SNS: Pub/Sub #
Topic에 publish 하면 모든 구독자에 즉시 전달.
모델 #
publish → Topic ──┬─→ 구독자 1 (Lambda)
├─→ 구독자 2 (SQS)
├─→ 구독자 3 (Email)
├─→ 구독자 4 (HTTP endpoint)
└─→ 구독자 5 (SMS)한 이벤트가 발생했을 때 여러 컴포넌트가 동시에 알아야 하는 경우.
만들기 + Publish #
TOPIC_ARN=$(aws sns create-topic --name user-events \
--query TopicArn --output text)
# Lambda 구독
aws sns subscribe \
--topic-arn $TOPIC_ARN \
--protocol lambda \
--notification-endpoint arn:aws:lambda:ap-northeast-2:123456789012:function:on-user-event
# Email 구독 (확인 메일 후 활성화)
aws sns subscribe \
--topic-arn $TOPIC_ARN \
--protocol email \
--notification-endpoint admin@example.com
# Publish
aws sns publish \
--topic-arn $TOPIC_ARN \
--message '{"userId":42,"action":"signup"}'Standard vs FIFO #
- Standard: 거의 무한 처리량, 순서 보장 없음, 중복 가능
- FIFO: 그룹 내 순서 보장, 정확히 한 번 전달. 처리량 제한 (3,000 msg/s with batching)
이름에 .fifo 접미사와 MessageGroupId가 필수입니다.
메시지 필터링 #
같은 Topic에 publish 되어도 구독자가 일부만 받도록 필터링할 수 있습니다.
aws sns set-subscription-attributes \
--subscription-arn $SUB_ARN \
--attribute-name FilterPolicy \
--attribute-value '{"event": ["signup", "purchase"]}'publish 시 MessageAttributes의 event가 일치할 때만 전달.
적합한 경우 #
- 한 이벤트 → 여러 처리 (이메일, 알림, 분석, 감사 로그)
- Email / SMS / Mobile Push 알림
- SQS fan-out의 입구
SQS: Queue #
Queue에 메시지를 넣으면 한 명의 소비자가 polling으로 가져가 처리.
모델 #
생산자 ─→ Queue ─→ 소비자 (Lambda / ECS Task)
↑
pull (polling)소비자가 받아가는 모델. 백프레셔가 자연스럽게 잡힙니다. 소비자가 느리면 Queue에 메시지가 쌓이지만, 그 동안 생산자는 영향을 받지 않습니다.
만들기 + Send / Receive #
QUEUE_URL=$(aws sqs create-queue --queue-name jobs \
--query QueueUrl --output text)
# Send
aws sqs send-message \
--queue-url $QUEUE_URL \
--message-body '{"job":"resize","key":"photo.jpg"}'
# Receive
aws sqs receive-message \
--queue-url $QUEUE_URL \
--max-number-of-messages 10 \
--wait-time-seconds 20 # long polling
# Delete (처리 완료 후)
aws sqs delete-message \
--queue-url $QUEUE_URL \
--receipt-handle <handle>Lambda와 자동 연결 #
Lambda에 SQS를 트리거로 붙이면 폴링 / 삭제를 Lambda 인프라가 자동으로 처리합니다.
aws lambda create-event-source-mapping \
--function-name process-jobs \
--event-source-arn arn:aws:sqs:ap-northeast-2:123456789012:jobs \
--batch-size 10 \
--maximum-batching-window-in-seconds 5def handler(event, context):
for record in event["Records"]:
body = json.loads(record["body"])
process_job(body)
# 정상 종료 → Lambda가 자동으로 메시지 삭제
# 예외 → 메시지 큐에 남아 visibility timeout 후 재시도Visibility Timeout: 가장 중요한 설정 #
소비자가 메시지를 받으면 N 초 동안 다른 소비자에 안 보이게 됩니다. 이 시간 안에 처리 + 삭제가 끝나야 함. 안 그러면 다시 큐에 떠 다른 소비자가 받음 → 중복 처리 위험.
| 설정 | 권장 |
|---|---|
| 평균 처리 시간 1초 | Visibility Timeout 30초 (여유) |
| 평균 처리 시간 30초 | 60~90초 |
| 매우 길어질 수 있는 처리 | change-message-visibility로 처리 중 연장 |
Standard vs FIFO #
SNS와 같음.
- Standard: 거의 무한 처리량, 순서 보장 없음, at-least-once (드물게 중복)
- FIFO: 그룹 내 순서, 정확히 한 번 (
MessageDeduplicationId)
Dead Letter Queue (DLQ) #
처리에 실패한 메시지를 별도 큐로 이송합니다. 운영 필수 항목입니다.
# DLQ 만들기
DLQ_URL=$(aws sqs create-queue --queue-name jobs-dlq \
--query QueueUrl --output text)
DLQ_ARN=$(aws sqs get-queue-attributes \
--queue-url $DLQ_URL --attribute-names QueueArn \
--query 'Attributes.QueueArn' --output text)
# Main queue에 redrive policy
aws sqs set-queue-attributes \
--queue-url $QUEUE_URL \
--attributes '{
"RedrivePolicy": "{\"deadLetterTargetArn\":\"'"$DLQ_ARN"'\",\"maxReceiveCount\":\"3\"}"
}'3회 retry 후 실패 → DLQ로 이송. DLQ의 메시지는 사람이 분석 / 수정 / 다시 큐로 보냄.
적합한 경우 #
- 작업 큐 (이미지 처리, 메일 발송, 외부 API 호출)
- 트래픽 스파이크 흡수
- 컴포넌트 분리 (생산자가 소비자 속도 영향 안 받음)
EventBridge: Event Bus #
EventBridge는 여러 소스에서 들어오는 이벤트를 여러 타겟에 룰 기반으로 라우팅.
모델 #
이벤트 소스 (S3, EC2 상태 변경, 외부 SaaS, 내 코드 ...)
│
▼
Event Bus (default 또는 사용자 정의)
│
├─ Rule A (패턴: source=aws.s3, eventName=ObjectCreated:Put)
│ → Lambda
├─ Rule B (패턴: source=myapp, detail-type=user.signup)
│ → SQS + Step Functions (둘 다 타겟)
└─ Rule C (cron: 매일 03:00)
→ Lambda (배치 작업)두 종류의 이벤트 #
1) AWS 서비스 이벤트. AWS가 자동 publish.
- EC2 상태 변경 (running → stopped)
- S3 ObjectCreated
- CodePipeline 단계 완료
- …
2) Custom 이벤트. 내 코드가 publish.
aws events put-events --entries '[{
"Source": "myapp.users",
"DetailType": "user.signup",
"Detail": "{\"userId\":42,\"plan\":\"pro\"}",
"EventBusName": "default"
}]'Rule 만들기 #
aws events put-rule \
--name on-user-signup \
--event-pattern '{
"source": ["myapp.users"],
"detail-type": ["user.signup"],
"detail": {"plan": ["pro"]}
}'
# 타겟 추가
aws events put-targets \
--rule on-user-signup \
--targets 'Id=1,Arn=arn:aws:lambda:ap-northeast-2:123456789012:function:welcome-pro'aws events put-rule \
--name nightly-cleanup \
--schedule-expression 'cron(0 18 * * ? *)' # UTC 18:00 = KST 03:00
aws events put-targets \
--rule nightly-cleanup \
--targets 'Id=1,Arn=arn:aws:lambda:ap-northeast-2:123456789012:function:cleanup'스케줄링은 더 깔끔한 도구로 EventBridge Scheduler가 따로 있습니다 (200,000개까지 / cron 또는 rate / 일회성 또는 반복). 새 프로젝트에서는 Scheduler를 우선 검토하세요.
Schema Registry / Pipes #
대규모 이벤트 생태계에서:
- Schema Registry: 이벤트의 스키마를 등록 / 자동 발견. 코드 생성기로 타입 안전한 클라이언트
- EventBridge Pipes: SQS / Kinesis / DynamoDB Streams → (선택적 enrichment / filter) → 타겟
적합한 경우 #
- AWS 서비스 이벤트에 반응 (S3 업로드 → 처리)
- 도메인 이벤트 라우팅 (
user.signup→ 5가지 처리) - 스케줄링 (cron). Lambda + EventBridge Scheduler가 표준
- SaaS 통합 (Datadog, PagerDuty, Stripe 등 매니지드 통합)
Fan-out 패턴 #
가장 흔한 운영 패턴 중 하나. 한 이벤트 → 여러 비동기 처리.
생산자 ─→ SNS Topic ──┬─→ SQS Queue A ─→ Lambda A
├─→ SQS Queue B ─→ Lambda B
└─→ SQS Queue C ─→ Lambda C왜 SNS + SQS 인가? Lambda를 SNS에 직접 붙여도 되지만 SQS를 한 단계 끼우면:
- 각 처리의 백프레셔가 독립 (B가 느려도 A는 영향 없음)
- 각 처리의 retry / DLQ가 독립
- Lambda가 잠시 죽어도 메시지가 SQS에 14일까지 보관
EventBridge도 같은 패턴. 한 이벤트가 여러 룰에 매칭되면 여러 타겟에 동시 전달.
멱등성 (Idempotency)의 중요성 #
비동기 시스템의 핵심. 같은 메시지를 두 번 받아도 결과가 같아야 한다.
왜 두 번 받는가:
- SQS Standard는 at-least-once. 가끔 중복
- Visibility Timeout 안에 처리 못 끝내면 재 전달
- Lambda 자동 retry (비동기 호출)
- 네트워크 / 클라이언트 재시도
패턴 1: 자연 멱등 연산 #
# 멱등 (몇 번을 해도 결과 같음)
user.set_status("active")
s3.put_object(Bucket=b, Key=k, Body=data)
# 비멱등
user.add_credit(100)
queue.send(...)가능하면 자연 멱등으로 설계.
패턴 2: ID + DB 마커 #
def handler(event, context):
msg = json.loads(event["body"])
msg_id = msg["id"]
# 이미 처리한 ID 인가?
if redis.get(f"processed:{msg_id}"):
return # skip
process(msg)
redis.setex(f"processed:{msg_id}", 86400, "1") # 1일 보관Lambda Powertools의 Idempotency가 이 패턴을 DynamoDB 백엔드로 깔끔하게.
패턴 3: FIFO Queue의 deduplication #
MessageDeduplicationId 또는 컨텐츠 기반 deduplication. 5분 안에 같은 ID면 자동 거부.
어느 도구를 언제 #
한 이벤트, 여러 받는 쪽 #
→ SNS Fan-out (+ SQS 끼우기) 또는 EventBridge
EventBridge가 풍부한 룰 / 필터 / AWS 서비스 통합을 제공합니다. 단순 fan-out만 필요하다면 SNS+SQS가 적합합니다.
작업 큐 #
→ SQS
AWS 서비스 이벤트에 반응 #
→ EventBridge (S3, EC2 등 자동 publish)
스케줄링 #
→ EventBridge Scheduler (또는 EventBridge Rule)
컴포넌트 간 단순 메시지 (1:1) #
→ SQS
Email / SMS / Mobile Push #
→ SNS
외부 SaaS 통합 #
→ EventBridge (매니지드 통합) 또는 EventBridge Pipes
비용: 짧게 #
| 가격 | |
|---|---|
| SQS | 100만 request당 $0.40 (Standard), $0.50 (FIFO) |
| SNS | publish 100만 당 $0.50 (Email / SMS / Mobile은 별도) |
| EventBridge | publish 100만 당 $1.00 (custom 이벤트), AWS 자체 이벤트 무료 |
월 1,000만 메시지의 SQS 비용은 $4입니다. 작은 워크로드에서는 사실상 무시할 수 있는 수준입니다.
자주 만나는 함정 #
1) 메시지 중복 처리 #
자연 멱등이 아닌 연산 (결제 / 크레딧 추가 등)을 SQS Standard에서 처리하면, 한 번의 결제가 두 번 발생할 수 있습니다. 항상 멱등 패턴을 적용하거나 FIFO를 사용하세요.
2) Visibility Timeout 미스 #
처리에 60초 걸리는데 Visibility Timeout이 30초라면, 처리 중인 메시지가 다시 큐에 나타나 다른 소비자가 가져가 두 번 처리됩니다. Visibility Timeout은 처리 시간에 여유를 더한 값으로 설정하세요.
3) DLQ 없음 #
실패한 메시지가 영원히 큐에 떠다님 → CloudWatch 알람만 시끄러움. 모든 큐에 DLQ + 알람. DLQ 자체에도 알람 (DLQ에 메시지 들어옴 = 사람이 봐야 함).
4) Lambda의 SQS 폴링이 비싸 보임 #
Lambda가 비어있는 큐를 빈도 높게 폴링 → SQS request 비용. long polling (WaitTimeSeconds=20)이 기본인지 확인.
5) EventBridge rule이 너무 많아짐 #
도메인 이벤트마다 룰 / 룰 / 룰 → 콘솔이 카오스. 도메인별로 사용자 정의 Event Bus (default가 아닌)를 분리, IaC로 관리.
6) SNS Email / SMS의 용도 #
SNS의 Email은 시각이 단조롭고 (텍스트만, From 변경 어려움) Spam 분류되기 쉬움. 트랜잭셔널 메일 (회원가입 등)은 Amazon SES가 정답. SNS Email은 운영자 알림 정도에만.
7) 비동기 처리 결과를 클라이언트에 알리는 방법 #
API → SQS → Lambda 처리 후 결과를 클라이언트에 어떻게? 두 패턴:
- 클라이언트가 polling (작업 ID로 GET 요청)
- WebSocket (API Gateway WebSocket API)으로 push
비동기 시스템 설계 시 처음에 정해야 할 기준.
정리 #
이번 글에서 잡은 것:
- 셋의 차이. SNS (pub/sub), SQS (queue), EventBridge (라우팅 룰)
- SNS. Topic에 publish, 여러 구독자에 즉시 push. Email / SMS / Mobile Push 통합
- SQS. Queue + polling. Visibility Timeout이 가장 중요한 설정
- DLQ. 모든 큐에 필수.
maxReceiveCount회 실패 후 이송 - Standard vs FIFO. Standard는 at-least-once / 무한 처리량. FIFO는 순서 + 중복 제거 + 처리량 제한
- EventBridge. AWS 서비스 이벤트 + custom 이벤트. 룰 패턴으로 라우팅. Scheduler로 cron
- Fan-out 패턴. SNS → 여러 SQS → 각 Lambda. 백프레셔 / retry / DLQ가 받는 쪽마다 독립
- 멱등성. at-least-once 환경에선 필수. 자연 멱등 / DB 마커 / FIFO dedup
- 선택 가이드. 한 이벤트 N 받기 (SNS / EventBridge), 작업 큐 (SQS), AWS 이벤트 반응 (EventBridge), 스케줄 (EventBridge Scheduler), Email (SES, SNS 아님)
- 비용. 모두 매우 저렴. 작은 워크로드는 무시
- 함정. 중복 처리, Visibility Timeout 미스, DLQ 누락, polling 비용 (long polling), 룰 폭주, SNS Email의 용도, 결과 알림 패턴
다음: 비밀 / 설정 #
다음 주제는 운영의 진지한 한 축, 비밀번호와 설정 값을 어디에 보관하느냐입니다.
#6 Secrets Manager / Parameter Store에서는 둘의 차이, 자동 회전, 코드에서 가져오기, IaC와의 연결, 비용 비교까지, AWS의 시크릿 관리 두 도구를 한 번에 정리하겠습니다.