이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • 어떤 기능이 MSA 분리 후보가 되는가?
  • 서비스 분리는 성능, 정합성, 장애 격리, 운영 복잡도 중 무엇을 얻고 무엇을 잃는가?
  • Monolith에서 바로 service를 만들지 않고 어떤 준비를 먼저 해야 하는가?

개요

MSA는 application을 여러 독립 service로 나누는 구조다. 좋은 MSA의 단위는 controller나 table이 아니라 책임과 owner다. 서비스가 나뉘려면 그 기능을 책임지는 팀, 데이터 owner, API 계약, 배포 권한, 장애 대응 책임이 함께 나뉘어야 한다. 단순히 코드가 많거나 트래픽이 늘었다는 이유만으로 나누면 network와 운영 복잡도만 증가한다. MSA 분리는 “더 멋진 구조”가 아니라 “분리 비용을 감수할 만큼 독립성이 필요한가”를 판단하는 일이다.

이 문서가 바꾸는 설계 축

바뀌는 내용
성능기능별 scale은 가능하지만 network latency와 serialization 비용이 생긴다.
정합성단일 transaction 대신 saga, event, read model, 보상 상태가 필요해진다.
장애 격리service별 장애 격리가 가능하지만 sync fanout은 장애 전파를 키운다.
운영 복잡도배포, tracing, alert, contract test, schema migration 단위가 늘어난다.

분리 후보 기준

기준분리 근거가 강한 경우약한 경우
팀 소유권payment 팀이 독립 roadmap과 on-call을 가진다.같은 팀이 모든 기능을 같이 배포한다.
데이터 소유권payment 데이터 write owner가 명확하다.여러 기능이 같은 table을 직접 수정한다.
배포 독립성결제 변경을 주문 배포와 분리해야 한다.항상 같은 release train으로 나간다.
장애 격리결제 장애가 주문 조회를 막으면 안 된다.장애 시 전체 기능을 같이 내리는 것이 허용된다.
scaling 차이알림 worker만 10배 scale해야 한다.모든 기능 트래픽 패턴이 비슷하다.
규제/보안결제, 개인정보, 정산처럼 접근 통제가 다르다.보안 경계가 동일하다.
이 중 하나만으로는 부족하다.
보통 여러 기준이 동시에 맞을 때 분리 근거가 강해진다.

대표 시나리오

주문 서비스에서 결제 기능을 분리할지 검토한다고 하자. 현재 문제는 다음과 같다.

결제 provider 변경이 월 6회 발생
주문 기능 배포는 주 1회 release train
결제 장애 때 주문 조회 p95가 2초 이상 증가
결제 테이블 schema 변경 승인자가 불명확
결제 로그와 알림 owner가 주문팀과 섞여 있음

이 상태에서 바로 service를 만들면 위험하다. 먼저 결제 module owner, table owner, API 계약, timeout, event, on-call 책임을 정해야 한다. 그 다음에도 독립 배포 요구가 남으면 service 분리를 검토한다.

분리하면 안 되는 경우

MSA가 문제를 키우는 경우도 많다. 다음 상황에서는 분리보다 module 정리가 먼저다.

  • 기능 경계가 계속 바뀐다.
  • 하나의 transaction으로 묶어야 하는 불변식이 많다.
  • 팀이 하나이고 on-call도 하나다.
  • service별 SLO와 alert를 운영할 수 없다.
  • shared DB를 유지할 계획이다.
  • synchronous call chain이 길어질 것이 명확하다. 이 경우 service 분리는 구조 개선이 아니라 latency와 장애 모델 추가가 된다.

분리 후보 평가표

후보ownerdatadeployfailure isolation판단
payment별도 팀 가능결제 table owner 명확독립 배포 필요주문 조회와 격리 필요강한 후보
notificationworker scale 차이 큼발송 이력 owner 명확비동기 가능장애 시 지연 허용강한 후보
coupon주문 transaction과 강하게 연결쿠폰/주문 동시 불변식 많음독립 배포 낮음장애 시 주문 영향 큼module 경계 우선
admin reportread 부하 큼source data owner 아님배포 독립 낮음read model로 격리 가능service보다 projection
평가표는 점수 놀이가 아니라 논의의 누락을 줄이는 도구다.

서비스 계약

Service 분리는 API 계약을 만든다. 결제 예약 API를 예로 들면 주문 서비스는 결제 내부 table을 알지 못해야 한다.

POST /payments/reservations
Idempotency-Key: order-123
 
{
  "orderId": "order-123",
  "memberId": "member-9",
  "amount": 42000
}

응답도 성공만 있으면 안 된다.

{
  "paymentReservationId": "pay-rsv-77",
  "status": "PENDING_AUTHORIZATION",
  "retryable": true
}

MSA에서는 pending, retryable, duplicate, timeout, unknown 상태가 API 계약에 들어와야 한다.

Sync와 Async 선택

서비스가 나뉘면 호출 방식이 설계 결정이 된다.

경계동기 호출 적합비동기 event 적합
결제 승인사용자 응답 전에 결과가 필요할 수 있다.승인 후 알림, 영수증
재고 예약실패 시 주문을 막아야 한다.재고 변경 projection
알림 발송대부분 동기 불필요발송 지연 허용
정산 집계사용자 요청과 분리batch/event 처리
동기 호출이 많아질수록 latency와 partial failure 비용이 커진다.
비동기 event는 사용자 응답을 빠르게 하지만 중복과 지연을 설계해야 한다.

분리 순서

MSA 전환은 새 repository를 만드는 일이 아니다. 안전한 순서는 보통 다음과 같다.

  1. Monolith 안에서 module boundary를 만든다.
  2. table owner와 public API를 정한다.
  3. 다른 module의 direct repository access를 제거한다.
  4. event/outbox와 idempotency를 도입한다.
  5. contract test와 observability를 준비한다.
  6. 일부 traffic 또는 한 기능부터 service로 뺀다.
  7. old path를 제거하기 전 rollback 기준을 둔다. 이 순서는 느려 보이지만 데이터 사고와 분산 monolith를 줄인다.

운영 준비도

다음이 없으면 분리 후 장애 대응이 어려워진다.

준비 항목필요한 이유
distributed tracing요청이 어느 service에서 느려졌는지 추적
service SLO장애 판단 기준 분리
contract testAPI 변경으로 다른 service를 깨뜨리지 않음
deployment rollback독립 배포의 실제 안전장치
owner/on-call장애와 schema 변경 책임 명확화
runbooktimeout, DLQ, lag, partial failure 대응

개인 프로젝트 기준

  • MSA를 구현하지 않아도 분리 후보 평가표를 작성한다.
  • shared DB를 유지하는 구조가 왜 위험한지 설명한다.
  • notification처럼 비동기 분리에 적합한 기능과 payment처럼 동기 판단이 필요한 기능을 구분한다.
  • API 계약에 pending, duplicate, timeout 응답을 넣어본다.
  • 포트폴리오에서는 “MSA로 나눴다”보다 “어떤 기준으로 나눴는가”를 먼저 말한다.

기업 운영 기준

  • service 분리 RFC에는 owner, data, API, SLO, migration, rollback, cost를 포함한다.
  • 분리 전후 latency와 incident blast radius를 비교한다.
  • shared DB 제거 계획이 없으면 MSA 승인 조건을 만족하지 못한 것으로 본다.
  • service별 dashboard와 alert를 배포 전에 만든다.
  • team topology와 service topology가 맞는지 정기적으로 검토한다.

위험 신호

  • controller 단위로 service를 나눈다.
  • 하나의 기능 요청이 5개 이상 service를 동기 호출한다.
  • service는 나뉘었지만 DB schema는 모든 팀이 수정한다.
  • API 계약 없이 내부 DTO를 그대로 노출한다.
  • tracing 없이 service를 늘린다.
  • 독립 배포를 말하지만 실제로는 모든 service를 같은 시간에 배포한다.

확인 질문

확인 질문

  • 확인 질문: MSA 분리 후보를 판단하는 핵심 기준은 무엇인가?
    • 답변: 팀 소유권, 데이터 소유권, 배포 독립성, 장애 격리 필요, scaling 차이, 운영 준비도다.
  • 확인 질문: shared DB가 남아 있으면 왜 분리 효과가 약한가?
    • 답변: schema 변경과 데이터 write 책임이 여전히 묶여 있어 독립 배포와 owner 분리가 깨지기 때문이다.
  • 확인 질문: MSA 분리 전 Monolith 안에서 먼저 해야 할 일은 무엇인가?
    • 답변: module boundary, public API, table owner, event/outbox, 관측과 contract test를 먼저 검증하는 것이다.