이벤트 기반 시스템

120

왜 이벤트 기반 시스템을 만들까?

여러분이 커머스 플랫폼의 백엔드 개발자라고 상상해 보세요. 고객이 주문을 하면 다음 일들이 동시에 일어나야 합니다:

이벤트 기반 아키텍처 — EventBridge로 서비스 간 느슨한 결합
  1. 주문 서비스: 주문 정보를 DB에 저장
  2. 재고 서비스: 재고 수량 차감
  3. 결제 서비스: 결제 처리
  4. 알림 서비스: 고객에게 확인 이메일 발송
  5. 분석 서비스: 주문 이벤트 로깅

만약 주문 서비스가 나머지 4개 서비스를 직접 호출한다면 어떤 문제가 생길까요?

  • 알림 서비스가 다운되면 주문 자체가 실패합니다 (강한 결합)
  • 분석 서비스를 새로 추가할 때마다 주문 서비스 코드를 수정해야 합니다
  • 결제 서비스가 느리면 전체 응답 시간이 느려집니다

이벤트 기반 아키텍처는 이 문제를 해결합니다. 주문 서비스는 "주문이 생성되었다"는 이벤트만 발행하고, 나머지 서비스들이 각자 그 이벤트를 구독하여 처리합니다. 서비스 간 직접적인 의존이 사라지고, 새 서비스를 추가해도 기존 코드를 건드릴 필요가 없습니다.

이 실습에서는 AWS EventBridge를 중심으로 느슨한 결합의 이벤트 기반 마이크로서비스를 구축합니다.

실습을 시작하기 전에 AWS 콘솔에 로그인되어 있는지 확인하세요. 리전은 ap-northeast-2 (서울) 을 사용합니다.

아키텍처 개요

직접 호출 vs 이벤트 기반 패턴 비교

이벤트 흐름

다이어그램 로딩 중...
EventBridge 기반 이벤트 라우팅 흐름

비용 예측

비용 계산기

2시간
0h24h
EventBridge

시간당 과금

$0.0200
Lambda

100만 요청당 $0.20 + 실행시간

$0.0040
SQS

요청 100만당 $0.40

$0.0020
SNS

요청 100만당 $0.50

$0.0020
예상 총 비용$0.0280

* 실제 비용은 AWS 요금 정책에 따라 달라질 수 있습니다.

Step 1: EventBridge 이벤트 버스 생성

이벤트 버스는 모든 이벤트가 흘러가는 "고속도로"입니다. 커스텀 버스를 만들어 애플리케이션 이벤트를 AWS 서비스 이벤트와 분리합니다.

  1. AWS 콘솔 상단에서 EventBridge 검색 후 클릭
  2. 왼쪽 메뉴에서 이벤트 버스 클릭
  3. 이벤트 버스 생성 클릭
  4. 이름: lab-event-bus 입력
  5. 리소스 정책: 기본값 유지 (같은 계정 내에서만 이벤트 발행 허용)
  6. 생성 클릭
  7. 목록에 lab-event-bus가 표시되는지 확인합니다 (기본 default 버스와 함께)
코드
aws events create-event-bus \
  --name lab-event-bus

커스텀 이벤트 버스를 사용하면 기본(default) 버스의 AWS 서비스 이벤트와 애플리케이션 이벤트를 분리하여 관리할 수 있습니다. 또한 다른 AWS 계정의 이벤트 버스와 연결하여 크로스 계정 이벤트 공유도 가능합니다.

Step 2: 이벤트 규칙 구성

이벤트 규칙은 "어떤 이벤트가 오면 어디로 보낼지"를 정의합니다. 이벤트의 source와 detail-type을 기준으로 패턴 매칭합니다.

  1. EventBridge 콘솔 → 왼쪽 메뉴 규칙 클릭
  2. 규칙 생성 클릭
  3. 이름: lab-order-created-rule
  4. 이벤트 버스: 드롭다운에서 lab-event-bus 선택 (기본 버스가 아닙니다!)
  5. 규칙 유형: 이벤트 패턴이 있는 규칙 선택
  6. 이벤트 패턴 섹션에서 사용자 지정 패턴 선택 후 아래 JSON 입력:
    코드
    {
      "source": ["lab.ecommerce"],
      "detail-type": ["order.created"]
    }
  7. 이 패턴은 "source가 lab.ecommerce이고 detail-type이 order.created인 이벤트만 매칭"합니다
  8. 다음 클릭 후 타겟 설정은 Step 3에서 진행합니다
코드
aws events put-rule \
  --name lab-order-created-rule \
  --event-bus-name lab-event-bus \
  --event-pattern '{
    "source": ["lab.ecommerce"],
    "detail-type": ["order.created"]
  }'

Step 3: SNS 알림 토픽 생성

결제 이벤트가 발생하면 관리자에게 이메일 알림을 보내기 위한 SNS 토픽을 만듭니다.

진행률 0/6
  1. 1AWS 콘솔에서 SNS 검색 → 클릭
  2. 2토픽 생성 → 유형: 표준 → 이름: lab-event-notification → 토픽 생성 클릭
  3. 3토픽 상세 페이지에서 구독 생성 클릭
  4. 4프로토콜: 이메일, 엔드포인트: 본인 이메일 주소 입력 → 구독 생성 클릭
  5. 5이메일 받은편지함에서 확인 링크 클릭 → SNS 콘솔에서 구독 상태가 확인됨으로 변경 확인
  6. 6메시지 발행 버튼으로 테스트 메시지 전송 → 이메일 수신 확인

SNS 구독 확인 이메일이 오지 않으면 스팸함을 확인하세요. "AWS Notification" 발신자로 오며, 24시간 내에 확인하지 않으면 구독이 만료됩니다.

Step 4: Lambda 타겟 연결

이벤트 규칙에 매칭된 이벤트를 처리할 Lambda 함수를 만들고 연결합니다.

진행률 0/7
  1. 1Lambda 콘솔 → 함수 생성 → 이름: lab-order-processor, 런타임: Python 3.12
  2. 2아래 코드를 붙여넣습니다 — 이벤트 데이터를 로그에 출력하고 처리 결과를 반환합니다: import json, logging logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): logger.info(f"주문 이벤트 수신: {json.dumps(event, ensure_ascii=False)}") order = event.get('detail', {}) logger.info(f"주문 ID: {order.get('orderId')}, 고객: {order.get('customer')}")
  3. 3Deploy 클릭
  4. 4EventBridge 콘솔로 돌아가서 lab-order-created-rule 편집 → 타겟 추가: lab-order-processor Lambda 선택
  5. 5같은 방식으로 결제 규칙 생성: 이름: lab-payment-completed-rule 이벤트 버스: lab-event-bus 패턴: {"source": ["lab.ecommerce"], "detail-type": ["payment.completed"]}
  6. 6결제 규칙의 타겟: SNS 토픽 lab-event-notification 연결
  7. 7Lambda 실행 역할에 AmazonDynamoDBFullAccess 정책 연결 (주문 데이터를 DynamoDB에 저장하려는 경우)

EventBridge 규칙 하나에 최대 5개의 타겟을 연결할 수 있습니다. 예를 들어 주문 이벤트를 Lambda(주문 처리), SQS(분석 로그), CloudWatch Logs(감사 로그)에 동시에 전달할 수 있습니다. 타겟마다 독립적으로 실행되므로 하나의 타겟이 실패해도 다른 타겟에 영향을 주지 않습니다.

Step 5: DLQ (Dead Letter Queue) 구성

이벤트 처리가 실패했을 때 이벤트를 잃어버리지 않도록 DLQ를 설정합니다.

  1. SQS 콘솔 → 대기열 생성 클릭
  2. 유형: 표준 대기열, 이름: lab-event-dlq
  3. 메시지 보존 기간: 14일 (실패 이벤트를 충분히 조사할 시간)
  4. 대기열 생성 클릭
  5. EventBridge 콘솔 → lab-order-created-rule 편집 → 타겟 설정에서 재시도 정책 및 DLQ 섹션 열기
  6. 재시도 횟수: 2회, 최대 이벤트 기간: 24시간
  7. DLQ: lab-event-dlq 선택
  8. 저장 후 Lambda 함수에서 의도적으로 에러를 발생시켜 DLQ에 메시지가 들어가는지 확인
코드
aws sqs create-queue \
  --queue-name lab-event-dlq \
  --attributes MessageRetentionPeriod=1209600

DLQ(Dead Letter Queue)는 처리에 실패한 이벤트를 보존하여 디버깅과 재처리에 활용할 수 있게 합니다. 프로덕션 환경에서 필수 구성입니다. DLQ에 메시지가 쌓이면 CloudWatch 알람을 설정하여 즉시 알림을 받을 수 있습니다.

Step 6: 이벤트 패턴 매칭 테스트

이벤트를 실제로 발행하여 전체 시스템이 동작하는지 확인합니다.

진행률 0/6
  1. 1Lambda 콘솔 → 함수 생성 → 이름: lab-event-producer, 런타임: Python 3.12
  2. 2아래 코드를 붙여넣습니다: import json, boto3, datetime client = boto3.client('events') def lambda_handler(event, context): response = client.put_events(Entries=[{ 'Source': 'lab.ecommerce', 'DetailType': 'order.created', 'Detail': json.dumps({ 'orderId': 'ORD-2024-001', 'customer': '홍길동', 'amount': 59000, 'items': ['AWS 교재', '스티커'], 'timestamp': datetime.datetime.now
  3. 3Lambda 실행 역할에 AmazonEventBridgeFullAccess 정책 연결
  4. 4Deploy 후 테스트 실행 — 빈 JSON {} 으로 실행
  5. 5CloudWatch Logs에서 lab-order-processor 함수의 로그를 확인합니다 — "주문 이벤트 수신" 메시지가 보이면 성공!
  6. 6결제 이벤트도 테스트: 코드에서 DetailType을 payment.completed로 변경 후 실행 → SNS 이메일 수신 확인

Step 7: 이벤트 아카이브 및 리플레이

과거 이벤트를 저장하고 필요할 때 재실행할 수 있는 기능을 설정합니다. 디버깅이나 새 서비스 테스트에 매우 유용합니다.

진행률 0/8
  1. 1EventBridge 콘솔 → 왼쪽 메뉴 아카이브 → 아카이브 생성 클릭
  2. 2이름: lab-event-archive
  3. 3소스 이벤트 버스: lab-event-bus 선택
  4. 4보존 기간: 7일 설정 (무기한도 가능하지만 비용 발생)
  5. 5아카이브 생성 클릭
  6. 6이벤트를 몇 건 발행한 후 리플레이 메뉴에서 리플레이 시작 클릭
  7. 7시간 범위를 선택하면 해당 기간의 아카이브된 이벤트가 다시 이벤트 버스로 전달됩니다
  8. 8CloudWatch Logs에서 Lambda가 다시 실행되는 것을 확인합니다

트러블슈팅

이벤트를 발행했는데 Lambda가 실행되지 않으면:

  1. 이벤트 버스 이름이 정확한지 확인 (lab-event-bus를 빼먹으면 기본 버스로 전달됨)
  2. 규칙의 이벤트 패턴에서 source와 detail-type이 발행한 이벤트와 정확히 일치하는지 확인 (대소문자 구분)
  3. 규칙 상태가 활성화인지 확인

Lambda 실행 역할 권한 에러: 이벤트 생산자 Lambda에는 events:PutEvents 권한이, 이벤트 소비자 Lambda에는 기본 실행 권한만 있으면 됩니다. EventBridge가 Lambda를 호출할 때는 EventBridge 자체 서비스 역할의 권한을 사용합니다.

DLQ에 메시지가 안 들어가면: EventBridge 규칙의 타겟 설정에서 DLQ를 설정했는지 확인하세요. 또한 EventBridge가 SQS에 메시지를 보내려면 SQS 대기열의 액세스 정책에서 EventBridge 서비스를 허용해야 합니다.

완성 후 통합 테스트 체크리스트

모든 구성 요소가 연결되었는지 최종 점검합니다.

진행률 0/5
  1. 1lab-event-producer Lambda에서 주문 이벤트 발행 → CloudWatch Logs에서 lab-order-processor 실행 확인
  2. 2결제 이벤트 발행 (payment.completed) → SNS 이메일 수신 확인
  3. 3lab-order-processor에서 의도적 에러 발생 → DLQ에 메시지 도착 확인
  4. 4EventBridge 아카이브에서 리플레이 실행 → Lambda가 다시 호출되는지 확인
  5. 5존재하지 않는 이벤트 타입 발행 → 어떤 규칙에도 매칭되지 않아 타겟이 실행되지 않음을 확인

핵심 개념 확인

확장 아이디어

기본 이벤트 시스템이 완성되었으니, 더 발전시켜 보세요:

  1. 이벤트 스키마 레지스트리: EventBridge Schema Registry로 이벤트 구조를 문서화하고 버전 관리
  2. 크로스 서비스 사가 패턴: 주문 → 결제 → 배송 순서의 분산 트랜잭션을 이벤트로 구현
  3. 이벤트 소싱: DynamoDB Streams + EventBridge로 상태 변경 이력을 이벤트로 관리
  4. 멀티 타겟 규칙: 하나의 이벤트를 Lambda, SQS, SNS, Step Functions 등 여러 타겟에 동시 전달
  5. 입력 변환기: EventBridge 규칙의 Input Transformer로 이벤트 데이터를 타겟에 맞게 가공

학습 정리

핵심 치트시트

리소스 정리

실습 완료 후 반드시 아래 순서대로 리소스를 정리하여 불필요한 과금을 방지하세요.

  1. EventBridge 아카이브 삭제
  2. EventBridge 규칙 삭제 (타겟 먼저 제거 후 규칙 삭제)
  3. EventBridge 이벤트 버스 삭제 (lab-event-bus)
  4. Lambda 함수 삭제 (producer, order-processor)
  5. SQS DLQ 삭제 (lab-event-dlq)
  6. SNS 토픽 및 구독 삭제
  7. IAM 역할 정리
  8. CloudWatch 로그 그룹 삭제