두 번째 프로젝트에서 주문 도메인을 담당하면서 MSA(Microservice Architecture) 와 Apache Kafka 를 도입했다.
단순히 유행하는 기술이라서가 아니라, 도메인 독립성과 서비스 간 결합도 문제를 해결하기 위한 선택이었다.
이 글에서는 왜 그 기술들을 선택했는지, 현재 구조의 한계는 무엇인지, 앞으로 어떻게 개선할지를 정리한다.
서비스를 설계하면서 도메인을 분리하는 과정에서 자연스럽게 "각 도메인이 얼마나 독립적으로 동작할 수 있는가?"라는 질문을 갖게 됐다.
모놀리식 구조에서는 하나의 도메인에 장애가 생기면 전체 서비스에 영향을 줄 수 있다는 점이 가장 큰 문제였다.
현재는 서버만 분리된 상태로, 각 서비스당 서버 1개 + DB 1개만 운영 중이다.
현재 구조
┌────────────┐ ┌────────────┐ ┌────────────┐
│ 주문 서버 │ │ 배송 서버 │ │ 사용자 서버 │
│ (1대) │ │ (1대) │ │ (1대) │
│ DB (1개) │ │ DB (1개) │ │ DB (1개) │
└────────────┘ └────────────┘ └────────────┘
이 구조에서는 장애 대응이 부족하다. 서버나 DB 중 하나라도 다운되면 해당 서비스 전체가 중단된다.
장애에 제대로 대응하려면 최소한 서버 2대, DB 이중화 구성이 필요하다.
목표 구조 (예시)
┌──────────────────────┐
│ 주문 서비스 │
│ 서버 1 ↕ 서버 2 │ ← Active-Active 또는 Active-Standby
│DB Primary - DB Replica│
└──────────────────────┘
다만, 이미 서버가 분리되어 있기 때문에 확장 자체는 어렵지 않다는 점은 MSA 도입의 실질적인 이점이다.
MSA 구조에서 서비스 간 통신을 REST API(동기 방식)로만 처리하면, 서비스 간 강한 결합(Tight Coupling) 이 생긴다.
예를 들어 주문 서비스가 결제 서비스를 직접 호출하는 구조라면, 결제 서비스가 다운됐을 때 주문 서비스도 함께 실패한다.
Kafka를 통한 서비스 간 통신 흐름
주문 서비스 → [Kafka Topic: order-created] → 배송 서비스
→ [Kafka Topic: order-created] → 재고 서비스
현재 가장 큰 아쉬운 점은 메시지 발행 실패 또는 처리 실패 시 롤백 처리가 없다는 것이다.
예를 들어 주문은 생성됐는데 Kafka 메시지 발행이 실패하면, 결제 서비스는 해당 주문을 인지하지 못한다.
이 경우 데이터 불일치 가 발생할 수 있다.
현재의 문제 상황
주문 생성 성공 → Kafka 발행 실패 → 재고 미처리 → 데이터 불일치 ❌
이를 해결하기 위해 다음 프로젝트에서는 Saga 패턴 또는 Transactional Outbox 패턴 도입을 검토할 예정이다.
개선 방향 (Outbox Pattern 예시)
주문 생성 + Outbox 테이블 기록 (같은 트랜잭션)
→ 별도 프로세스가 Outbox를 읽어 Kafka 발행
→ 발행 성공 시 Outbox 레코드 처리 완료 표시
| 기술 | 도입 이유 | 현재 한계 | 개선 방향 |
|---|---|---|---|
| MSA | 도메인별 독립성, 장애 격리, 확장 용이성 | 서버/DB 단일 구성으로 장애 대응 부족 | 서버 이중화, DB Replication |
| Kafka | 서비스 간 결합도 감소, 비동기 통신 | 메시지 실패 시 롤백/보상 트랜잭션 없음 | Saga 패턴 또는 Outbox 패턴 도입 |
기술을 도입할 때 "왜 이 기술을 쓰는가"만큼 중요한 건 "현재 무엇이 부족한가"를 아는 것이라고 생각한다.
이번 프로젝트에서 확인한 한계들을 다음 프로젝트에서 하나씩 보완해 나갈 예정이다.