[IT 잡썰] 이벤트 기반 아키텍처

이벤트 기반 아키텍처는 분산 시스템에서 컴포넌트가 서로 직접 통신하지 않고, 이벤트를 통해 간접적으로 상호작용하는 설계 방안입니다. 이를 통해 각 구성 요소가 독립적으로 운영되며 확장성과 유연성이 높아집니다. 주요 구성 요소와 함께 이벤트 기반 아키텍처가 분산화에 적합한 이유는 다음과 같습니다.

이벤트 기반 아키텍처의 핵심 개념

  • 이벤트(Event): 시스템 내의 상태 변화를 의미합니다. 예를 들어, “주문 완료”, “결제 완료” 등의 사건이 발생하면 해당 이벤트가 발행됩니다.
  • 이벤트 브로커(Event Broker): 이벤트를 발행하고 구독할 수 있는 중앙 허브 역할을 하며, Kafka, RabbitMQ, AWS SNS/SQS 등이 자주 사용됩니다.
  • 발행자(Publisher)와 구독자(Subscriber): 이벤트를 발생시키는 발행자와 이벤트를 수신하고 이에 응답하는 구독자가 독립적으로 존재하며, 발행자와 구독자는 서로를 알 필요 없이 이벤트 브로커를 통해 통신합니다.

이벤트 기반 아키텍처의 특징

  • 독립적인 서비스 운영: 서비스들이 직접 통신하지 않고 이벤트로 연결되므로 각각의 서비스는 독립적으로 배포, 확장, 운영이 가능합니다.
  • 확장성: 구독자가 늘어나거나 줄어드는 일이 서비스 운영에 영향을 미치지 않기 때문에 분산화된 서비스 구성에서 확장성이 용이합니다.
  • 비동기 통신: 이벤트가 발생하면 브로커에 전달되고 구독자들은 비동기 방식으로 이벤트를 처리할 수 있어 높은 성능을 유지할 수 있습니다.

분산화 측면에서의 장점

  • 높은 유연성: 새로운 서비스나 기능이 추가될 때 기존 서비스에 대한 수정 없이 브로커에 새 구독자를 추가함으로써 확장이 가능합니다.
  • 결합도 감소: 서비스 간의 결합도를 낮추어 각 서비스가 독립적으로 유지보수와 운영이 가능하므로 시스템의 전체적인 유연성이 향상됩니다.
  • 복원력: 서비스 장애가 발생하더라도 이벤트가 브로커에 쌓이므로 복구 시 이벤트를 순차적으로 처리하여 데이터를 잃지 않게 보장할 수 있습니다.

설계 시 고려사항

  • 이벤트 순서 보장: 이벤트가 순서대로 처리되어야 할 경우 특별한 설계가 필요합니다. 예를 들어, Kafka는 파티셔닝을 통해 순서 보장을 지원합니다.
  • 데이터 일관성: 비동기 방식으로 데이터 일관성을 유지하는 데 주의해야 하며, 필요 시 보상 트랜잭션 또는 이벤트 소싱을 통해 최종 일관성을 보장할 수 있습니다.
  • 모니터링과 로깅: 분산화된 이벤트 흐름을 추적하기 위해 중앙 모니터링과 로깅 시스템을 활용하는 것이 중요합니다. 로그 집계를 통해 장애 상황을 신속하게 파악할 수 있도록 합니다.

이벤트 기반 아키텍처의 예시

이벤트 기반 아키텍처를 실제로 구현하는 과정에서는 여러 요소와 설계 고려사항을 단계별로 검토해야 합니다. 여기서는 전자상거래 시스템을 예로 들어, 결제 및 배송 프로세스를 중심으로 하는 이벤트 기반 아키텍처 솔루션 설계를 설명하겠습니다.

요구사항 분석 및 아키텍처 설계

요구사항
  • 결제 완료 시 배송 시스템에서 자동으로 배송 준비가 되어야 합니다.
  • 주문 상태 변경을 트래킹해야 하며, 고객에게 알림을 전송해야 합니다.
  • 결제, 배송, 알림 서비스는 독립적으로 배포 및 확장 가능해야 합니다.
아키텍처 설계
  • 이벤트 브로커 선택: Apache Kafka를 이벤트 브로커로 사용하여 메시지를 관리할 수 있습니다. Kafka는 고성능, 파티셔닝을 통한 확장성, 그리고 순서 보장을 제공합니다.
  • 서비스 정의:
    • Order 서비스: 주문을 생성하고 관리하며, 결제 완료 이벤트를 발행.
    • Payment 서비스: 결제 완료 시 이벤트를 발행.
    • Shipping 서비스: 결제 완료 이벤트를 구독해 상품을 준비 및 배송.
    • Notification 서비스: 모든 이벤트(주문 생성, 결제 완료, 배송 완료 등)를 구독하여 고객에게 상태를 알림.

이벤트 흐름 및 데이터 설계

이벤트 정의
주문 생성: { "eventType": "ORDER_CREATED", "orderId": "123", "userId": "abc", "amount": 100.0 }

결제 완료: { "eventType": "PAYMENT_COMPLETED", "orderId": "123", "paymentId": "789" }

배송 준비 완료: { "eventType": "SHIPPING_READY", "orderId": "123", "shippingId": "456" }

이벤트 메시지는 JSON 형식으로 정의하며, 각 이벤트에 대한 타입, ID, 주요 정보들을 포함하여 구독자가 해당 이벤트를 식별할 수 있도록 합니다.

서비스 구현

이벤트 발행자와 구독자 설계

각 서비스는 이벤트 브로커(Kafka)를 통해 간접적으로 통신합니다.

  • Order 서비스
    • 주문 생성 시 ORDER_CREATED 이벤트 발행.
    • 결제 서비스가 결제 완료 시, PAYMENT_COMPLETED 이벤트 수신.
  • Payment 서비스
    • 결제 완료 시 PAYMENT_COMPLETED 이벤트 발행.
    • 결제가 완료되면 Order 서비스에 별도 요청 없이 결제 완료 이벤트를 발행합니다.
  • Shipping 서비스
    • PAYMENT_COMPLETED 이벤트를 구독하여 배송 준비 수행 후 SHIPPING_READY 이벤트를 발행.
    • 배송이 완료되면 고객에게도 알림 전송.
  • Notification 서비스
    • 모든 이벤트를 구독하여 적절한 알림을 사용자에게 전송합니다.
이벤트 처리 흐름
  1. Order 서비스가 주문을 생성하고 ORDER_CREATED 이벤트를 발행합니다.
  2. Payment 서비스는 결제 완료 후 PAYMENT_COMPLETED 이벤트를 발행합니다.
  3. Shipping 서비스는 PAYMENT_COMPLETED 이벤트를 구독하여, 해당 주문의 배송 준비를 수행하고 SHIPPING_READY 이벤트를 발행합니다.
  4. Notification 서비스는 각 이벤트를 구독하여 주문 생성, 결제 완료, 배송 준비 완료 등의 상태 변경 알림을 고객에게 전달합니다.
코드 예시 (간단한 Kafka Publisher & Subscriber)

다음은 Kafka로 PAYMENT_COMPLETED 이벤트를 발행하고 구독하는 Java 코드 예시입니다.

// Publisher: Payment 서비스에서 이벤트 발행
Producer<String, String> producer = new KafkaProducer<>(properties);
String message = "{ \"eventType\": \"PAYMENT_COMPLETED\", \"orderId\": \"123\", \"paymentId\": \"789\" }";
producer.send(new ProducerRecord<>("payment-events", "123", message));
producer.close();

// Subscriber: Shipping 서비스에서 이벤트 구독
Consumer<String, String> consumer = new KafkaConsumer<>(properties);
consumer.subscribe(Arrays.asList("payment-events"));

while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
    for (ConsumerRecord<String, String> record : records) {
        // Process payment completed event
        System.out.printf("Received payment event: %s%n", record.value());
    }
}

시스템 확장과 장애 처리 설계

확장성

  • 서비스 간 직접 호출이 아닌 이벤트 발행/구독 방식이므로, 각 서비스는 독립적으로 확장할 수 있습니다. 예를 들어, 트래픽이 높은 Notification 서비스는 구독자 수를 늘려 확장할 수 있습니다.

장애 처리

  • 이벤트가 일시적으로 지연되거나 일부 서비스가 다운되는 경우, Kafka는 메시지를 재전송하거나 메시지 보존 기간 내에 누락 없이 다시 제공할 수 있어 복구가 용이합니다.
  • 이벤트 저장을 통해 복원력이 증가하고, 장애 발생 시 이벤트 재처리를 통해 데이터 일관성도 유지할 수 있습니다.

모니터링 및 로깅

모니터링을 위해 Prometheus와 Grafana를 활용하여 각 서비스 상태와 이벤트 지연 시간을 시각화합니다. 로그는 ELK(Elasticsearch, Logstash, Kibana) 스택을 통해 중앙 관리하여, 이벤트 처리 흐름을 추적하고 장애 발생 원인을 파악하는 데 유용합니다.

이벤트 기반 아키텍처는 시스템의 결합도를 낮추고, 독립적인 서비스 개발과 배포를 가능하게 하여, 대규모 시스템에서 높은 유연성과 확장성을 제공합니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다