실습 예제 · 8
EventBridge 이벤트 아키텍처
큐가 한 소비자에게 일을 넘기는 구조라면, 이벤트 버스는 일어난 사실을 알리고 관심 있는 쪽이 각자 반응하는 구조입니다. 생산자는 소비자가 몇인지 알 필요가 없고, 소비자를 늘려도 생산자를 고치지 않습니다.
학습 목표
- 사용자 지정 이벤트 버스를 만들고 이벤트를 게시할 수 있습니다.
- 이벤트 패턴으로 필요한 이벤트만 골라 대상에 전달할 수 있습니다.
- 대상별 재시도 정책과 배달 못한 편지 대기열을 설정할 수 있습니다.
- SNS 팬아웃과 EventBridge 라우팅의 구조적 차이를 설명할 수 있습니다.
- 예약 규칙으로 주기적인 작업을 트리거할 수 있습니다.
시나리오
주문 서비스가 이벤트를 게시하고, 여러 팀이 각자 반응합니다.
- 주문이 생성되면 알림 팀이 메일을 보냅니다.
- 주문이 취소되면 정산 팀이 환불을 처리합니다.
- 금액이 일정 기준을 넘는 주문은 심사 팀이 검토합니다.
- 새 팀이 생겨도 주문 서비스 코드를 고치지 않아야 합니다.
마지막 조건이 이벤트 버스를 고르는 이유입니다. 구독자를 추가하는 일이 규칙 하나를 만드는 일로 끝납니다.
아키텍처 개요
| 항목 | Amazon SNS 팬아웃 | Amazon EventBridge |
|---|---|---|
| 전달 방식 | 주제를 구독한 모든 대상에 브로드캐스트 | 이벤트 패턴에 맞는 규칙의 대상에만 전달 |
| 필터링 | 구독 필터 정책으로 메시지 속성 기준 | 이벤트 본문 구조 전체를 패턴으로 매칭 |
| 대상 종류 | 큐·함수·HTTP·이메일 등 | 훨씬 다양한 AWS 서비스 |
| AWS 서비스 이벤트 | 직접 받지 않는다 | 기본 버스로 들어온다 |
| 스키마 | 정의되지 않는다 | 스키마 레지스트리로 관리할 수 있다 |
이 실습은 사용자 지정 버스를 씁니다. AWS 서비스가 내보내는 이벤트는 기본 버스로 들어오므로, 애플리케이션 이벤트를 섞지 않으려면 버스를 나누는 편이 관리하기 쉽습니다.
구성 단계
1 · 사용자 지정 이벤트 버스
aws events create-event-bus \
--name lab08-orders-bus \
--query 'EventBusArn' --output text
2 · 이벤트 형태 정하기
EventBridge 이벤트는 Source · DetailType · Detail 세 가지가 핵심입니다.
이 셋을 규칙에서 매칭하므로, 처음에 명명 규칙을 정해 두면 나중이 편합니다.
aws events put-events --entries '[
{
"EventBusName": "lab08-orders-bus",
"Source": "example.orders",
"DetailType": "OrderCreated",
"Detail": "{\"orderId\":\"ord-1001\",\"customerId\":\"cust-001\",\"totalAmount\":42000}"
}
]'
3 · 규칙과 대상
{
"source": ["example.orders"],
"detail-type": ["OrderCreated"]
}
{
"source": ["example.orders"],
"detail-type": ["OrderCreated"],
"detail": {
"totalAmount": [{ "numeric": [">=", 1000000] }]
}
}
aws events put-rule \
--name lab08-order-created \
--event-bus-name lab08-orders-bus \
--event-pattern file://rule-created.json \
--state ENABLED
aws events put-targets \
--rule lab08-order-created \
--event-bus-name lab08-orders-bus \
--targets '[
{
"Id": "notify-fn",
"Arn": "arn:aws:lambda:ap-northeast-2:123456789012:function:lab08-notify",
"RetryPolicy": { "MaximumRetryAttempts": 2, "MaximumEventAgeInSeconds": 3600 },
"DeadLetterConfig": {
"Arn": "arn:aws:sqs:ap-northeast-2:123456789012:lab08-events-dlq"
}
}
]'
aws events put-rule \
--name lab08-high-value \
--event-bus-name lab08-orders-bus \
--event-pattern file://rule-high-value.json \
--state ENABLED
aws events put-targets \
--rule lab08-high-value \
--event-bus-name lab08-orders-bus \
--targets '[
{
"Id": "review-queue",
"Arn": "arn:aws:sqs:ap-northeast-2:123456789012:lab08-review"
}
]'
4 · 대상 호출 권한
실습 6과 같은 구조입니다. 대상 쪽에 "EventBridge가 호출해도 된다"는 권한이 있어야 합니다.
RULE_ARN=$(aws events describe-rule \
--name lab08-order-created \
--event-bus-name lab08-orders-bus \
--query 'Arn' --output text)
aws lambda add-permission \
--function-name lab08-notify \
--statement-id eventbridge-order-created \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn "$RULE_ARN"
SQS 큐가 대상이면 큐 정책에
events.amazonaws.com의 sqs:SendMessage를 허용하고,
조건으로 규칙 ARN을 지정합니다.
5 · 예약 규칙
aws events put-rule \
--name lab08-nightly-reconcile \
--schedule-expression "cron(0 18 * * ? *)" \
--state ENABLED
aws events put-targets \
--rule lab08-nightly-reconcile \
--targets '[{
"Id": "reconcile-fn",
"Arn": "arn:aws:lambda:ap-northeast-2:123456789012:function:lab08-reconcile"
}]'
검증 방법
패턴을 먼저 시험한다
규칙을 만들기 전에 패턴이 실제 이벤트와 맞는지 확인할 수 있습니다. 이벤트가 전달되지 않는 문제의 대부분은 패턴 불일치입니다.
aws events test-event-pattern \
--event-pattern '{"source":["example.orders"],"detail-type":["OrderCreated"]}' \
--event '{
"id": "test-1",
"source": "example.orders",
"detail-type": "OrderCreated",
"account": "123456789012",
"region": "ap-northeast-2",
"time": "2026-07-29T10:00:00Z",
"resources": [],
"detail": { "orderId": "ord-1001", "totalAmount": 42000 }
}' \
--query 'Result'
aws events list-rules \
--event-bus-name lab08-orders-bus \
--query 'Rules[].[Name,State,EventPattern]' --output table
aws events list-targets-by-rule \
--rule lab08-order-created \
--event-bus-name lab08-orders-bus \
--query 'Targets[].[Id,Arn]' --output table
# 게시 결과에서 실패 항목 수를 확인합니다.
aws events put-events --entries '[{
"EventBusName":"lab08-orders-bus",
"Source":"example.orders",
"DetailType":"OrderCreated",
"Detail":"{\"orderId\":\"ord-1002\",\"totalAmount\":2000000}"
}]' \
--query '[FailedEntryCount, Entries]'
| 항목 | 기대 결과 |
|---|---|
| 일반 주문 이벤트 | 알림 대상만 호출된다 |
| 고액 주문 이벤트 | 알림과 심사 양쪽 규칙에 모두 매칭된다 |
다른 Source의 이벤트 |
어느 규칙에도 매칭되지 않는다 |
| 권한이 없는 대상 | 전달이 실패하고 재시도 후 DLQ로 간다 |
FailedEntryCount |
0이어야 한다 |
비용 고려
| 항목 | 성격 |
|---|---|
| 사용자 지정 이벤트 | 게시한 이벤트 수 |
| AWS 서비스 이벤트 | 기본 버스로 들어오는 이벤트의 취급이 다르다 |
| 대상 호출 | 호출되는 대상 서비스(Lambda·SQS 등)의 요금이 별도로 발생한다 |
| 아카이브와 재생 | 보관한 이벤트 양과 재생한 이벤트 수 |
| 재시도 | 실패가 반복되면 대상 호출이 늘어난다 |
비용을 좌우하는 것은 이벤트 수입니다. 모든 상태 변화를 이벤트로 만들면 양이 빠르게 늘어납니다. "누군가 반응해야 하는 사실"만 이벤트로 만들고, 내부 상태 변화는 이벤트로 올리지 않는 편이 좋습니다.
프로덕션 고려사항
- 이벤트 이름 규칙을 먼저 정합니다.
Source는 도메인,DetailType은 과거형 사실 (OrderCreated,PaymentFailed)로 통일하면 규칙이 단순해집니다. - 스키마를 관리합니다. 생산자가 필드를 바꾸면 소비자가 조용히 깨집니다.
필드는 추가만 하고 제거·의미 변경은 새
DetailType으로 처리합니다. - 대상마다 DLQ를 붙입니다. 전달 실패는 조용히 사라지는 것이 가장 나쁩니다.
- 아카이브와 재생을 켜 두면 소비자 버그를 고친 뒤 과거 이벤트를 다시 흘려보낼 수 있습니다.
- 버스를 나눕니다. AWS 서비스 이벤트와 애플리케이션 이벤트를 섞지 않습니다.
- 교차 계정 전달이 필요하면 버스 리소스 정책으로 다른 계정의 게시를 허용합니다.
- 순서가 필요하면 이벤트 버스가 아닙니다. EventBridge는 순서를 보장하지 않습니다. 순서가 요구되면 FIFO 큐나 스트림을 씁니다.
정리 — 리소스 삭제
aws events remove-targets \
--rule lab08-order-created \
--event-bus-name lab08-orders-bus \
--ids notify-fn
aws events delete-rule \
--name lab08-order-created \
--event-bus-name lab08-orders-bus
aws events remove-targets \
--rule lab08-high-value \
--event-bus-name lab08-orders-bus \
--ids review-queue
aws events delete-rule \
--name lab08-high-value \
--event-bus-name lab08-orders-bus
aws events remove-targets --rule lab08-nightly-reconcile --ids reconcile-fn
aws events delete-rule --name lab08-nightly-reconcile
aws events delete-event-bus --name lab08-orders-bus
자주 하는 실수
| 실수 | 증상 | 고치는 법 |
|---|---|---|
EventBusName을 빠뜨림 |
이벤트가 기본 버스로 가서 규칙에 잡히지 않는다 | 게시와 규칙 양쪽에 버스 이름을 명시한다 |
Detail을 객체로 전달 |
게시가 실패한다 | JSON을 문자열로 인코딩한다 |
FailedEntryCount를 확인하지 않음 |
일부 이벤트가 조용히 유실된다 | 응답을 확인하고 실패 시 재시도한다 |
| 대상에 호출 권한이 없음 | 규칙은 매칭되는데 아무 일도 일어나지 않는다 | 리소스 기반 정책이나 큐 정책을 추가한다 |
| 사용자 지정 버스에 일정 표현식 | 동작하지 않는다 | 예약 규칙은 기본 버스에 만든다 |
| 일정 표현식을 현지 시각으로 작성 | 의도한 시각과 다르게 실행된다 | UTC로 환산하거나 시간대를 명시한다 |
| DLQ 없이 운영 | 전달 실패가 흔적 없이 사라진다 | 대상마다 배달 못한 편지 대기열을 지정한다 |
이어서 볼 곳
- 12장 · 서버리스와 애플리케이션 통합 EventBridge와 SNS·SQS의 역할 구분, 호출 모델 3종을 정면으로 다룹니다.
- 실습 7 · SQS + Lambda 비동기 처리 큐로 결합을 끊는 방식과 비교해 보면 두 패턴의 용도가 분명해집니다.
- 실습 6 · Lambda + API Gateway REST API 동기 호출 경로의 권한 구성과 비교합니다.
- 케이스 7 · 트래픽 급증에 스케일아웃이 못 따라갔다 느슨한 결합이 확장성과 장애 격리에 어떻게 기여하는지 다룹니다.
- 실습 12 · CloudWatch 알람 + SNS 알림 이벤트 전달 실패를 지표와 알람으로 감시하는 구성을 만듭니다.
공식 문서 출처
- Amazon EventBridge API 레퍼런스 — PutRule — 이벤트 패턴과 일정 표현식, 버스 지정
- Amazon EventBridge API 레퍼런스 — PutTargets — 대상별 재시도 정책과 배달 못한 편지 대기열 설정
- Amazon EventBridge API 레퍼런스 — PutEvents
— 항목의
Source·DetailType·Detail구조와FailedEntryCount응답 - Amazon EventBridge API 레퍼런스 — TestEventPattern — 패턴과 이벤트의 매칭 여부 확인
- Amazon EventBridge API 레퍼런스 — CreateEventBus — 사용자 지정 버스 생성
- Amazon EventBridge API 레퍼런스 — CreateArchive — 이벤트 아카이브와 보존 기간
- AWS Lambda API 레퍼런스 — AddPermission — 대상 함수에 호출 주체를 허용하는 방식