이 프로젝트는 모놀리식 주문 시스템을 MSA(Microservice Architecture)로 리팩토링하고,
서비스 간 데이터 정합성을 보장하기 위해 Kafka 기반 Saga 패턴(보상 트랜잭션)을 적용한 주문 처리 시스템입니다.
최종 목표는 서비스 간 강결합 없이, 장애 상황에서도 데이터 일관성을 유지하며
확장성과 복원력을 갖춘 분산 아키텍처를 설계하는 것입니다.
| 서비스 명 | 주요 역할 |
|---|---|
| api-gateway | 외부 요청 라우팅, JWT 인증 수행 |
| eureka | 서비스 디스커버리 및 로드밸런싱 관리 |
| member-service | 회원 정보 및 인증 관리 |
| product-service | 상품 정보 및 재고 관리 |
| ordering-service | 주문 생성, 상태 변경, 보상 트랜잭션 수행 |
| 구성 요소 | 역할 |
|---|---|
| Kafka (KRaft) | 이벤트 브로커, 서비스 간 비동기 통신 |
| MariaDB | 서비스별 데이터 저장소 |
| Redis | 세션 캐시 및 임시 데이터 저장 |
| Docker Compose | 로컬 개발 환경 컨테이너 오케스트레이션 |
flowchart LR
A[Client] -->|JWT Token 요청| B[API Gateway]
B -->|Service Discovery| C[Eureka]
B --> D[Ordering Service]
D -->|OrderCreated Event| E[(Kafka)]
E --> F[Product Service]
F -->|StockUpdated Event| E
E -->|Consume Event| D
D -->|State Update| G[(MariaDB)]
F -->|Update Stock| H[(MariaDB)]
D -->|Cache Management| I[(Redis)]
ordering-service에서 주문 생성 (status = PENDING) ORDER_CREATED)를 Kafka로 발행 product-service가 이벤트 수신 후 재고를 차감 ORDER_SUCCESS 이벤트 발행 ordering-service가 성공 이벤트를 수신 후 상태를 COMPLETE로 변경 status = PENDING) ORDER_CREATED) 발행 product-service에서 재고 부족으로 실패 처리 ORDER_FAIL 이벤트 발행 ordering-service가 이벤트 수신 후 주문 상태를 CANCEL로 변경 (보상 트랜잭션 수행) CREATE → PENDING → COMPLETE
↘ CANCEL
MSA 환경에서는 하나의 트랜잭션으로 여러 서비스의 작업을 묶기 어려우며,
2PC(2-Phase Commit) 방식은 성능 저하와 복잡도를 초래합니다.
따라서 이벤트 기반 보상 트랜잭션(Saga Pattern)을 통해 다음을 달성했습니다.
ORDER_CREATED) ORDER_SUCCESS, ORDER_FAIL 이벤트 수신 COMPLETE, CANCEL) ORDER_FAIL, 성공 시 ORDER_SUCCESS 이벤트 발행 orderId + productId 기준으로 멱등성(Idempotency) 처리 문제: 주문 생성 시 product-service를 동기 호출 → 장애 전파
해결: Kafka 기반 비동기 이벤트 전송 구조로 전환 및 Saga 도입
효과: 장애 격리, 처리 지연 감소, 서비스 확장 용이
문제: 주문 생성 성공 후 재고 차감 실패 시 상태 불일치
해결: 실패 이벤트 수신 시 주문 상태를 CANCEL 처리
효과: 분산 환경에서도 데이터 정합성 유지
문제: Kafka는 at-least-once 방식으로 동작하여 중복 이벤트 발생 가능
해결: orderId + productId 기반 멱등성 로직 적용
효과: 중복 처리 방지, 재고 정합성 유지
문제: 외부에서 내부 API 직접 접근 가능
해결: 내부 서비스는 Private Subnet에서만 접근 허용, Gateway만 Public으로 노출
효과: 인증 우회 차단, 네트워크 레벨 보안 강화
문제: 서비스 인스턴스 확장 시 포트 충돌 발생
해결: server.port=0 설정 → 동적 포트 할당, Eureka 기반 로드밸런싱 적용
효과: 인스턴스 단위 확장성 확보
ORDER_CREATED){
"eventType": "ORDER_CREATED",
"orderId": 1023,
"memberId": 7,
"productId": 31,
"quantity": 2,
"timestamp": "2026-03-05T15:20:00Z"
}
ORDER_SUCCESS){
"eventType": "ORDER_SUCCESS",
"orderId": 1023,
"productId": 31,
"remainingStock": 98,
"timestamp": "2026-03-05T15:20:03Z"
}
ORDER_FAIL){
"eventType": "ORDER_FAIL",
"orderId": 1023,
"productId": 31,
"reason": "재고 부족",
"timestamp": "2026-03-05T15:20:02Z"
}
POST /api/orders
{
"memberId": 7,
"productId": 31,
"quantity": 2
}
{
"orderId": 1023,
"status": "PENDING",
"message": "Order successfully created. Awaiting stock confirmation."
}
GET /api/orders/{orderId}
{
"orderId": 1023,
"memberId": 7,
"productId": 31,
"status": "COMPLETE"
}
# 1. 인프라 실행
docker-compose up -d
# 2. Spring Boot 애플리케이션 실행 순서
# 반드시 Eureka → Gateway → Member → Product → Ordering 순으로 실행
1. eureka
2. api-gateway
3. member-service
4. product-service
5. ordering-service