본문 바로가기

아키텍처|설계

이벤트 드리븐 아키텍처(EDA) 완벽 가이드 - 실전 예제로 배우는 비동기 시스템 설계

Event Event Event 아키텍처/설계 이벤트 드리븐 아키텍처 Event-Driven Architecture { event → handler }

이벤트 드리븐 아키텍처(EDA) 완벽 가이드 - 실전 예제로 배우는 비동기 시스템 설계

마이크로서비스가 대세가 되면서 서비스 간 느슨한 결합과 확장성이 그 어느 때보다 중요해졌어요. 이벤트 드리븐 아키텍처(Event-Driven Architecture, EDA)는 이러한 요구사항을 해결하는 핵심 설계 패턴입니다.

H2: 이벤트 드리븐 아키텍처란?

이벤트 드리븐 아키텍처는 시스템 내에서 발생하는 상태 변화(이벤트)를 중심으로 동작하는 설계 방식이에요. 전통적인 요청-응답 방식과 달리, 이벤트 발행자(Publisher)는 이벤트를 발생시키기만 하고, 이를 구독하는 소비자(Subscriber)가 독립적으로 처리하죠.

핵심 구성 요소:

  • 이벤트: 시스템에서 발생한 의미 있는 상태 변화 (예: 주문 생성, 결제 완료)
  • 이벤트 프로듀서: 이벤트를 생성하고 발행하는 주체
  • 이벤트 브로커: 이벤트를 전달하는 메시지 큐 (Kafka, RabbitMQ 등)
  • 이벤트 컨슈머: 이벤트를 구독하고 처리하는 서비스

이 방식의 가장 큰 장점은 서비스 간 직접적인 의존성이 없다는 거예요. 주문 서비스는 결제 서비스가 어떻게 동작하는지 몰라도 되고, 단지 "주문이 생성되었다"는 이벤트만 발행하면 됩니다.

H2: EDA의 핵심 패턴

1. 이벤트 알림(Event Notification)
가장 기본적인 패턴으로, 단순히 "무언가 일어났다"는 사실만 전달해요. 상세 정보는 API 호출로 별도 조회합니다.

2. 이벤트 소싱(Event Sourcing)
모든 상태 변화를 이벤트로 저장하는 패턴이에요. 현재 상태는 이벤트들을 재생해서 만들어내죠. 완벽한 감사 로그와 시점 복원이 가능합니다.

3. CQRS(Command Query Responsibility Segregation)
읽기와 쓰기를 분리하는 패턴으로, EDA와 함께 자주 사용돼요. 쓰기는 이벤트로 처리하고, 읽기는 최적화된 별도 저장소를 사용합니다.

H2: 실전 코드 예제 - Spring Boot + Kafka

주문 생성 시 재고 차감과 알림 발송을 이벤트로 처리하는 예제예요.

// 이벤트 발행
@Service
public class OrderService {
    @Autowired
    private KafkaTemplate<String, OrderEvent> kafkaTemplate;

    public void createOrder(Order order) {
        orderRepository.save(order);
        OrderEvent event = new OrderEvent(order.getId(), order.getUserId());
        kafkaTemplate.send("order-created", event);
    }
}
// 이벤트 소비
@Service
public class InventoryService {
    @KafkaListener(topics = "order-created")
    public void handleOrderCreated(OrderEvent event) {
        inventory.decreaseStock(event.getOrderId());
        log.info("재고 차감 완료: {}", event.getOrderId());
    }
}

이렇게 하면 OrderService는 재고 관리나 알림 로직을 전혀 몰라도 되고, 새로운 기능 추가 시에도 기존 코드 수정이 필요 없어요.

H2: EDA 도입 시 주의사항

1. 이벤트 순서 보장
분산 환경에서 이벤트 순서가 뒤바뀔 수 있어요. Kafka의 파티션 키나 메시지 시퀀스 번호로 해결할 수 있습니다.

2. 멱등성 처리
같은 이벤트가 중복 전달될 수 있으니, 컨슈머는 멱등하게 설계해야 해요. 이벤트 ID를 저장해서 중복 체크하는 방식이 일반적입니다.

3. 장애 전파 최소화
한 컨슈머의 실패가 다른 서비스에 영향을 주지 않도록 Dead Letter Queue와 재시도 전략이 필수예요.

4. 디버깅 복잡도
비동기 처리 특성상 트랜잭션 추적이 어려워요. 분산 추적 도구(Zipkin, Jaeger) 도입을 권장합니다.

H2: 결론

이벤트 드리븐 아키텍처는 현대 마이크로서비스 환경에서 확장성과 유연성을 제공하는 강력한 패턴이에요. 서비스 간 느슨한 결합으로 독립적인 배포와 확장이 가능하고, 새로운 기능을 기존 시스템 변경 없이 추가할 수 있죠. 다만 이벤트 순서 보장, 멱등성 처리, 장애 복구 전략 등 분산 시스템 특유의 복잡도를 이해하고 적절히 대응해야 합니다. 작은 범위부터 시작해서 점진적으로 확장하는 것을 추천해요.