11/13

졸용·2025년 11월 13일

TIL

목록 보기
114/144

🔹 Orchestrator란?

오케스트레이터(orchestrator)는 한 줄로 말하면 “여러 마이크로서비스를 순서대로 / 조건대로 움직이게 만드는 지휘자 역할의 컴포넌트”를 말한다.

근데 이 단어가 두 군데에서 쓰여서 헷갈리기 좋다:

  1. 인프라 레벨 오케스트레이터

    • 예: Kubernetes → 컨테이너(파드)를 여러 노드에 알아서 배치·확장·복구해 주는 애
    • “서비스 인스턴스를 어디에 몇 개 띄울지” 같은 운영 관점의 오케스트레이션
  2. 비즈니스/도메인 레벨 오케스트레이터

    • 예: Order → Payment → Inventory → Shipping 같은 비즈니스 흐름을 조립하고 관리하는 서비스
    • “어떤 서비스들을 어떤 순서로, 실패하면 어떻게 롤백(보상)할지” 같은 업무 흐름 관점의 오케스트레이션

이번 프로젝트의 MSA에서 필요한 건 보통 2번이라 이걸 위주로 알아보았다.



🔹 왜 오케스트레이터가 필요한가?

MSA에서는 기능이 이렇게 쪼개져 있다:

  • 주문 서비스(Order)
  • 결제 서비스(Payment)
  • 재고 서비스(Inventory)
  • 배송 서비스(Shipping)
  • 알림 서비스(Slack / Email 등)

“주문 생성”이라는 유스케이스 하나를 처리하려고 해도:

  1. 주문 레코드 생성 (Order)
  2. 결제 승인 (Payment)
  3. 재고 차감 (Inventory)
  4. 배송 정보 생성 (Shipping)
  5. 고객/담당자 알림 (Slack)

이렇게 여러 서비스가 순차적으로/조건적으로 협업해야 함.
이때 흐름을 관리하는 방법이 크게 두 가지로 볼 수 있다:

🔸 Choreography (합주, 춤추듯 알아서)

  • 각 서비스가 이벤트를 발행하고, 다른 서비스들이 그 이벤트를 구독해서 자기 할 일을 함.

  • 예:

    • OrderCreated 이벤트 발행 → Payment가 듣고 결제 시도 → PaymentCompleted 이벤트 발행 → Inventory가 듣고 재고 차감 …

장점:

  • 중앙 집중 지점 없음 → 유연, 느슨한 결합

단점:

  • 플로우가 여기저기 흩어져서 전체 비즈니스 흐름을 파악하기 어려움
  • 복잡해지면 “이 이벤트 어디서 누구 때문에 나간 거야?” 디버깅 지옥

🔸 Orchestration (지휘자)

  • Orchestrator 서비스/엔진이 중앙에서 전체 흐름을 알고 있음.
  • “1번 성공하면 2번 호출, 실패하면 1번 보상 호출” 같은 로직이 오케스트레이터에 모여 있음.

장점:

  • 비즈니스 프로세스 흐름을 한 곳에서 눈으로 보기 쉬움
  • 분산 트랜잭션(Saga)같은 걸 구현할 때 상태·보상 로직 관리가 쉽다

단점:

  • 과하게 쓰면 “거대한 God Service”가 될 수 있음
  • 중앙에 의존 → 장애/병목 지점(SPOF) 가능성


🔹 MSA에서 오케스트레이터를 어떻게 쓰나?

대표적인 사용처는:

🔸Saga Orchestrator (분산 트랜잭션 조정자)

예시: “주문 + 결제 + 재고 + 배송” 전체를 하나의 논리적 트랜잭션처럼 다루고 싶다.

  • Orchestrator가 하는 일:

    1. OrderService.createOrder() 호출

    2. 성공하면 PaymentService.approvePayment() 호출

      • 실패하면 OrderService.cancelOrder() 보상 호출
    3. 성공하면 InventoryService.decreaseStock() 호출

      • 실패하면 PaymentService.cancelPayment() + OrderService.cancelOrder() 보상 호출
    4. 성공하면 ShippingService.createShipment() 호출

    5. 끝나면 SlackService.notify() 호출

상태는 보통 Orchestrator DB에 이렇게 저장:

  • 현재 스텝 (ORDER_CREATED / PAYMENT_DONE / INVENTORY_DONE …)
  • 각 단계 성공/실패 여부
  • 보상(Compensation) 수행 여부

이게 보통 말하는 오케스트레이션 기반 Saga 패턴이다.


🔸 장기 실행/워크플로우 관리

예: “휴면 전환 프로세스”, “배송 마감 시한 계산 후 담당자에게 DM, 이후 상태 업데이트” 같은
몇 시간~며칠 걸릴 수 있는 흐름도 오케스트레이터로 관리할 수 있음.

  • 타임아웃, 재시도, 일정 지연(예: 24시간 후 다시 시도), 분기 조건(주문 상태가 X면 Y 수행)을
    Orchestrator가 가진 워크플로우 정의에 따라 실행.

이럴 때는 직접 코딩하기보단 아래 같은 워크플로우/오케스트레이션 엔진을 쓰기도 함:

  • Camunda / Zeebe
  • Temporal
  • Netflix Conductor
  • (단순하게는) Spring Batch + Scheduler 조합

🔸 외부 시스템/서드파티 연동 조정

예: 주문 하나 처리할 때

  • 내부 Order, Payment, Inventory
  • 외부 PG사, 외부 택배사 API
  • 슬랙/이메일 알림

이렇게 섞여 있으면, 실패 지점이 많고 보상 논리도 복잡해짐.
이때 오케스트레이터가

  • “어디까지 성공했는지”
  • “어떤 외부 호출이 성공/실패했는지”
  • “어떤 보상 호출을 했는지”

를 한 곳에서 추적해주면 운영이 훨씬 편해진다.



🔹 Spring / MSA 프로젝트에서 실제로 적용하는 그림

예를 들어 이번 프로젝트에서 하고 있는 스타일로 보면:

  • order-service
  • hub-service
  • shipping-service
  • slack-service
  • ai-service (최종 발송 시한 계산)
  • orchestrator-service (새로 하나 둔다고 가정)

🔸 예시 흐름 (최종 발송 시한 + Slack DM 연동)

sequenceDiagram
    autonumber
    actor Owner as "사장님(주문자)"
    participant UI as "주문 UI"
    participant Orc as "Orchestrator Service"
    participant Order as "Order Service"
    participant Hub as "Hub Service"
    participant AI as "AI Service"
    participant Slack as "Slack Service"

    Owner->>UI: 주문 생성 요청
    UI->>Orc: POST /orchestrations/orders {orderRequest}
    Orc->>Order: POST /orders
    Order-->>Orc: 주문 정보 + orderId

    Orc->>Hub: GET /hubs/{hubId}
    Hub-->>Orc: 허브 운영시간/정보

    Orc->>AI: POST /ai/deadline {orderId, hubInfo}
    AI-->>Orc: finalDeadline, slackFormattedText

    Orc->>Slack: POST /v1/slack/post-deadline {receiverSlackId, slackFormattedText}
    Slack-->>Orc: OK

    Orc-->>UI: 전체 처리 결과(주문 + 최종 발송 시한 + Slack 발송 여부)

여기서 Orchestrator 역할:

  • 단일 API로 복잡한 여러 서비스 호출을 감싸기

  • 중간에 실패하면:

    • 주문만 생성된 상태면 Order.cancel(orderId)
    • AI만 실패했으면 Slack은 스킵, 나중에 재요청 큐에 넣기
  • 전체 프로세스의 로그/상태를 한 곳에서 관리



🔹 구현 패턴 (Spring 기준)

🔸 직접 오케스트레이터 서비스 만들기

  • orchestrator-service 라는 별도 마이크로서비스

  • 이 안에:

    • OrchestrationInstance 엔티티 (각 프로세스 인스턴스)
    • 현재 스텝, 상태, 관련 ID들(orderId, paymentId 등)을 저장
    • Step별 메서드 or State Machine 구조로 구현

기술 스택 예:

  • 통신: Feign Client + Eureka + LoadBalancer, 또는 Kafka/RabbitMQ 이벤트
  • 트랜잭션: 각 서비스는 자기 로컬 트랜잭션만 커밋, 전체는 Saga로 묶기
  • 재시도/딜레이: R4j(Resilience4j) + Scheduler or 메시지 큐

🔸 워크플로우 엔진 사용

오케스트레이션이 복잡해지고 “상태 머신 + 타이머 + 시각화”까지 필요하면:

  • BPMN/Workflow 엔진을 붙여서 플로우를 다이어그램으로 설계한 뒤
  • 각 Task를 “OrderService 호출 Task”, “SlackService 호출 Task” 같이 모듈화

장점:

  • 시각화 / 운영 툴 / 모니터링이 잘 되어 있음
    단점:
  • 러닝 커브 + 인프라 구성 비용


🔹 언제 오케스트레이터를 쓰는 게 좋나?

도입 고려 기준을 요약하면:

  • ✅ 여러 서비스가 순차/조건/분기/재시도를 포함한 복잡한 플로우로 엮여 있다
  • ✅ 분산 트랜잭션(Saga)에서 보상 로직이 많고 복잡하다
  • ✅ “이 유스케이스가 어디서 어디까지 어떻게 흐르는지 한눈에 보고 싶다”
  • ✅ 운영팀/기획자도 “프로세스 상태”를 보고 싶어 한다

반대로:

  • ❌ 단순히 Order → Payment 딱 2번 호출 정도면
    → 그냥 Order 서비스 안에서 Feign으로 Payment 호출 + 예외 처리 정도로 충분할 때가 많음
  • ❌ 모든 걸 중앙으로 끌어모아서 Orchestrator가 또 다른 Monolith가 되면 안 됨

정리하면,

오케스트레이터는 여러 마이크로서비스의 호출 순서, 조건, 실패 시 보상까지 “시나리오 단위”로 관리하는 중앙 지휘자고,
MSA에서 Saga, 장기 프로세스, 외부 연동처럼 복잡한 비즈니스 흐름을 다룰 때 유용하게 쓸 수 있다.

profile
꾸준한 공부만이 답이다

0개의 댓글