Spring Cloud + Kafka로 구현하는 마이크로서비스 이벤트 아키텍처

Kafka를 이용한 이벤트 드리븐 아키텍처의 마이크로서비스 통신에 대해 알아봅시다!

📌 1. 들어가기

1-1. 왜 마이크로서비스 간 통신 방식이 중요할까요?

마이크로서비스 아키텍처는 애플리케이션을 작은 독립적인 서비스로 나누어 개발, 배포 및 확장성을 극대화할 수 있게 해줍니다.

하지만 서비스 간에 데이터와 명령을 어떻게 주고받을지가 시스템의 확장성, 성능 그리고 신뢰성에 영향을 미칩니다. 그래서 서비스 간 통신 방식에 대한 고민이 중요한 포인트가 됩니다.

가장 흔히 사용되는 두 가지 통신 방식은 다음과 같습니다.

  1. REST API 기반 통신 (동기 방식, Synchronous)
  2. Message Queue를 활용한 Event driven 통신 (비동기 방식, Asynchronous)

이전에 MSA에 관한 통신 방법들의 장단점을 비교하는 포스트를 작성했었습니다. 이번 포스트와 함께 읽어보시면 좋을 것 같습니다.

1-2. REST API 기반 통신의 한계점

REST API를 활용한 동기 통신은 마이크로서비스 초기 구현 시 간단하게 적용할 수 있고, HTTP를 이용한 요청/응답 패턴은 친숙하기에 가장 많이 선택되는 방식입니다.

하지만, 서비스 규모가 커질수록 REST API 통신의 한계점에 직면하게 됩니다.

강한 결합 (Tightly Coupled)

  • 문제: 서비스 A가 서비스 B의 API를 호출해야 한다면, 서비스 B가 반드시 정상 동작하고 있어야 합니다.
  • 예시: Order ServicePayment Service의 API를 호출했는데, 결제 서비스가 다운되면 주문 생성 자체가 실패하게 됩니다.

확장성 및 성능 이슈

  • 문제: 동기식 호출로 인해 요청이 병목 지점이 됩니다.
  • 예시: Order Service가 주문 생성 -> 결제 요청 -> 배송 요청까지 순차적으로(동기식)으로 호출한다면, 전체 응답 시간이 길어지게 됩니다. 결국 전체 트랜잭션이 느려지고, 동시에 많은 요청을 처리하기 어려워질 수 있습니다.

장애 전파

  • 문제: 하나의 서비스 장애가 연쇄적으로 다른 서비스에 영향을 줄 수 있습니다. 이는 단일 장애가 전체 시스템의 문제로 확산될 수 도 있습니다.
  • 예시: 결제 시스템이 느려지거나 장애가 발생하면, 주문 처리 시스템도 정상적으로 작동할 수 없습니다.

높은 종속성

  • 문제: API 구조 변경 시, 이를 호출하는 모든 서비스에 영향을 미칩니다. 이로 인해 각 서비스의 독립성이 낮아지고, 배포시 서비스 간의 조율이 필요합니다.

1-3. ✅ 요약

REST API 방식은 단순하고 직관적이지만, 확장성, 신뢰성, 유연성 측면에서 한계가 발생합니다.

2. Kafka 기반 이벤트 드리븐(Event-driven) 아키텍처

앞서 살펴본 동기식 통신의 한계점을 극복하기 위해 대규모의 MSA 환경에서는 Kafka 기반의 비동기 이벤트 통신을 사용하는 것이 적합합니다.

Kafka는 메시지 브로커 역할을 수행하면서, 서비스 간에 비동기 메시지를 전달해주는 역할을 합니다. 서비스들은 토픽(Topic)에 메시지를 발행(Publish)하거나 구독(Subscribe)함으로써 서로 통신할 수 있게 됩니다.

2-1. 이벤트 드리븐(Event-driven) 아키텍처의 장점

느슨한 결합 (Loosely Coupled)

  • 장점: 서비스 간 직접적인 호출이 없으므로, 서로의 존재를 몰라도 됩니다. 따라서 특정 서비스가 다운되더라도 전체 시스템에는 영향이 적습니다.
  • 예시: Order ServiceORDER_CREATED 주문 생성 이벤트만 발행하고, 이를 Payment Service에서 구독해서 처리합니다. 즉, 각 서비스들은 독립적으로 이벤트를 처리합니다.

비동기 처리로 인한 성능 향상

  • 장점: 요청을 큐에 넣고 바로 응답을 줄 수 있어, 빠른 처리가 가능합니다. 빠른 응답은 사용자의 경험을 개선해줍니다.
  • 예시: 사용자가 주문을 생성하면, 주문 ID를 바로 응답받고, 결제 및 배송처리는 백엔드에서 비동기로 진행됩니다.

장애 격리 및 내결함성 (Fault Tolerance)

  • 장점: Kafka에 발행된 메시지는 디스크에 저장되므로, 구독자가 잠시 다운되어도 메시지 재처리가 가능합니다. 따라서 서비스 장애 발생 시에도 데이터 유실 없이 복구가 가능합니다.
  • 예시: Payment Service가 다운되어도, Kafka에 쌓인 ORDER_CREATED 메시지를 서비스 복구 후 다시 처리할 수 있습니다.

확장성과 유연성

  • 장점: 서비스 간에 직접적인 통신을 하지 않기 때문에 확장성이 높아지고, 독립적으로 서비스 배포가 가능합니다. 이로써 새로운 서비스를 쉽게 추가할 수 있습니다.
  • 예시: Order Service에서 발행하는 이벤트를 구독하는 새로운 서비스를 추가해도 기존 시스템에 영향이 없습니다.

2-2. ✅ 요약

Kafka 기반 이벤트 드리븐 아키텍처는 확장성, 유연성, 내결함성 등 여러 측면에서 유리합니다.

3. 개선 과정: REST API → Kafka 기반 아키텍처로 전환

3-1. 기존 구조: REST API 기반

Order -> Payment -> Delivery 흐름을 REST API로 처리하면 다음 과정들이 동기식으로 이루어집니다.

  1. 사용자가 주문 생성 요청 -> Order Service
  2. Order Service가 결제 요청 -> Payment Service
  3. 결제 성공 시 배송 요청 -> Delivery Service

REST API 기반 방식의 문제점은 서비스 간 강한 결합으로 인해, 일부 과정 중 장애가 발생 시 전페 프로세스가 실패하게 됩니다. 즉 전체 트랜잭션이 모든 서비스들의 성공 여부에 종속하게 됩니다.

3-2. 개선된 구조: Kafka 이벤트 드리븐 기반

Kafka를 도입하여 각 단계에서 이벤트를 발행하고, 필요한 서비스가 이를 구독하는 구조로 전환합니다.

  1. 사용자가 주문 생성 요청을 하면 Order ServiceORDER_CREATED 이벤트를 Kafka에 발행합니다.
  2. Payment Service가 주문 생성 메시지를 구독하여 결제 처리를 진행합니다.
  3. 결제 성공 시 PAYMENT_COMPLETED 결제 성공 이벤트를 발행합니다.
  4. Delivery Service가 결제 성공 이벤트를 구독하여 배송 요청을 처리합니다.

Kafka를 도입함으로써 비동기 처리로 인한 빠른 사용자 응답이 가능해집니다. 서비스 간 느슨한 결합과 Kafka의 내결함성 덕분에 장애 전파 영향도 최소화 됩니다. 그리고 각각의 서비스들이 독립적으로 배포가 가능하고, 신규 서비스 추가가 용이해집니다.

4. 🚨 Kafka 기반 이벤트 아키텍처 설계 시 고려사항

메시지 중복 처리

  • 이벤트가 중복으로 전달될 수 있기 때문에, 수신자 측에 중복 방지 로직을 구현해야 합니다.

데이터 정합성

  • 비동기 구조로 인해 데이터 정합성이 깨질 수 있습니다.
  • 해결책으로 Sage 패턴 또는 Outbox 패턴을 도입할 수 있습니다.

에러 핸들링 및 보상 트랜잭션

  • 특정 이벤트 처리 실패에 대해 비즈니스 실패 케이스를 처리하기 위한 보상 트랜잭션 설계가 필요합니다.

Kafka 모니터링 및 운영

  • Kafka의 토픽, 메시지 적재량, Lag 등을 모니터링하여 적절한 대응을 할 수 있도록 해야 합니다.
  • Kafka가 SPOF(Single Point Of Failure)이 되지 않도록 멀티 클러스터로 운영할 필요가 있습니다.

5. 추가로 공부하면 좋을 내용

  • Kafka의 At-Least-Once/Exactly-Once 보장 방식
  • Kafka 멀티 클러스터 구성
  • Saga 패턴과 보상 트랜잭션

6. 💡 정리

  • REST API 기반 동기식 통신은 초기에는 빠르게 개발 가능하지만, 확장성과 유연성 측면에서 한계가 존재합니다.
  • Kafka를 활용한 이벤트 드리븐 아키텍처는 서비스 간 결합도를 낮추고, 장애 격리 및 확장성 측면에서 뛰어난 이점을 제공합니다.
  • 하지만, 이벤트 기반 시스템을 설계할 때는 중복 처리, 데이터 정합성, 에러 핸들링과 같은 추가적인 고려 사항을 반드시 신경써야 합니다.

궁극적으로 서비스 규모가 커질수록 Kafka 기반의 이벤트 드리븐 아키텍처는 성능과 유연성 측면에서 REST API 방식보다 장점이 많다고 볼 수 있습니다.