개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

Event Driven Architecture — 이벤트 발생을 중심으로 서비스가 협력하는 방식

2025년 1월 3일
EDAEvent DrivenPub/SubEvent BusProducer

서비스가 서로를 직접 호출하는 구조에서는 한 서비스가 느려지면 호출한 쪽도 함께 멈춘다. Event Driven Architecture는 이 결합을 끊기 위해 서비스 간 협력의 매개체를 "이벤트"로 바꾼다. 발생한 사실을 기록하고 흘려보내면, 관심 있는 서비스가 알아서 반응하는 방식이다.

핵심 구성 요소

Event는 시스템에서 발생한 사실을 나타내는 불변 메시지다. OrderPlaced, PaymentCompleted처럼 과거형 동사로 이름을 짓는다.

Producer는 이벤트를 생성해 Event Bus로 전달한다. 누가 이 이벤트를 받는지 알지 못한다.

Consumer는 관심 있는 이벤트를 구독해 처리한다. Producer와 직접 통신하지 않는다.

Event Bus는 이벤트를 수신하고 Consumer에게 전달하는 중간 인프라다. Kafka, RabbitMQ, AWS SNS/SQS 등이 이 역할을 맡는다.

[Order Service]
      |
   이벤트 발행 (OrderPlaced)
      |
      v
[  Event Bus  ]
      |
   ┌──┴──────────────┐
   v                 v
[Inventory Service] [Notification Service]
  재고 차감            이메일 발송

Message Queue와의 차이

Message Queue는 일반적으로 1:1 통신이다. 메시지를 하나의 Consumer가 소비하면 사라진다. Pub/Sub 패턴은 1:N이다. 하나의 이벤트가 구독 중인 모든 Consumer에게 전달된다.

항목Message QueuePub/Sub
수신자1개다수
소비 후 메시지삭제유지 가능
대표 도구RabbitMQ, SQSKafka, SNS
주 용도작업 분산이벤트 브로드캐스트

Pub/Sub 패턴

Topic에 이벤트를 발행하면, 해당 Topic을 구독한 모든 서비스가 이벤트를 수신한다. Consumer는 독립적으로 처리하기 때문에 서로 영향을 주지 않는다.

// Producer — 이벤트 발행
await eventBus.publish("order.placed", {
  orderId: "abc-123",
  userId: "user-456",
  amount: 39000,
});

// Consumer — 이벤트 구독
eventBus.subscribe("order.placed", async (event) => {
  await inventoryService.decrease(event.orderId);
});

Topic: 이벤트를 분류하는 채널. Producer는 Topic에 발행하고 Consumer는 Topic을 구독한다.

장단점

장점

  • 서비스 간 결합도가 낮다. Consumer를 추가해도 Producer 코드를 수정하지 않는다.
  • Consumer가 일시적으로 다운돼도 이벤트가 Event Bus에 쌓이므로 데이터가 유실되지 않는다.
  • 서비스별 독립 배포와 독립 스케일링이 쉽다.

단점

  • 흐름이 코드에 명시적으로 드러나지 않아 디버깅이 어렵다.
  • 이벤트 순서 보장이 필요한 경우 설계가 복잡해진다.
  • Consumer가 이벤트를 중복 수신할 수 있으므로 idempotency 처리가 필요하다.

Idempotency: 같은 작업을 여러 번 실행해도 결과가 동일한 성질. 중복 이벤트 처리 시 부작용을 막기 위해 필수다.

실무 예시

이커머스에서 주문이 완료되면 하나의 OrderPlaced 이벤트가 발행된다. 재고 서비스는 재고를 차감하고, 알림 서비스는 이메일을 보내고, 정산 서비스는 매출을 기록한다. 세 서비스는 서로를 모르고, Order Service도 이들을 직접 호출하지 않는다. 새로운 서비스가 필요하면 같은 Topic을 구독하는 Consumer를 추가하는 것으로 끝난다.

← 이전 글Message Queue — 서비스 간 비동기 메시지를 처리하는 큐
다음 글 →Domain Driven Design — 비즈니스 도메인을 중심으로 설계하는 방법