[아키텍처 #4] MSA(Microservices) — 서비스 경계, DB 소유, 그리고 Saga

Go 아키텍처 시리즈

  1. #1 Clean Architecture
  2. #2 Hexagonal & MessageQueue
  3. #3 Event-Driven Architecture
  4. #4 Microservices(MSA) — 지금 이 글

시리즈의 마지막. 1~3편이 “한 서비스 안을 어떻게 나누나”였다면, MSA는 “시스템을 여러 서비스로 어떻게 쪼개나”다. Microservices Architecture(MSA)는 하나의 큰 애플리케이션을 독립 배포 가능한 작은 서비스들로 나누고, 각자 자기 데이터를 소유하게 하는 방식이다.

1. 한 장으로 보는 그림

MSA — 게이트웨이·서비스별 DB 소유·비동기 이벤트 버스 (원본 제작)
MSA — 게이트웨이·서비스별 DB 소유·비동기 이벤트 버스 (원본 제작)

2. MSA를 지탱하는 원칙

원칙 내용
독립 배포 서비스마다 별도 저장소·파이프라인. 하나를 바꿔도 전체 재배포 없음
DB per Service 서비스가 자기 DB를 소유. 남의 DB를 직접 조회하지 않는다
API Gateway 클라이언트 진입점. 인증·라우팅·집계를 한곳에서
동기+비동기 혼합 즉시 응답은 REST/gRPC(동기), 파급은 이벤트(비동기)

가장 자주 어기는 게 DB per Service다. 두 서비스가 같은 테이블을 공유하면 배포가 서로 묶여 “분산 모놀리스”가 된다 — MSA의 비용은 다 치르고 이점은 못 얻는 최악의 상태.

3. 한 서비스 = 1~3편의 육각형

MSA는 1~3편을 버리지 않는다. 서비스 하나하나가 그대로 Hexagonal 육각형이다. 안쪽엔 UseCase+Domain, 왼쪽엔 HTTP 핸들러와 MQ Consumer(구동), 오른쪽엔 Repository와 MQ Publisher(피구동). 서비스 간 통신이 그 좌우 어댑터를 통해 이뤄질 뿐이다.

4. 분산 트랜잭션 — Saga

DB가 서비스마다 흩어지면 하나의 큰 트랜잭션으로 묶을 수 없다. 그래서 Saga를 쓴다 — 여러 로컬 트랜잭션을 이벤트로 이어 붙이고, 중간에 실패하면 보상 트랜잭션(compensating tx)으로 되돌린다.

주문 Saga (choreography 예)
  Order:    OrderCreated 발행
  Payment:  결제 시도 → PaymentSettled  (실패 시 PaymentFailed)
  Inventory:재고 차감 → StockReserved   (실패 시 StockFailed)
            └ 실패 이벤트 수신 시 → Order가 OrderCancelled 로 보상

여기서도 이벤트의 발행/소비는 2·3편의 규칙 그대로다. 3편의 Outbox가 Saga의 신뢰성을 떠받친다.

5. 언제 MSA를 쓰지 말아야 하나

MSA는 조직·트래픽이 커져 모놀리스의 배포·확장이 병목일 때 값을 한다. 반대로 작은 팀·초기 제품에서는 네트워크 지연, 분산 디버깅, 운영 복잡도라는 비용만 먼저 온다. 정석 조언은 여전히 유효하다 — “모놀리스로 시작하고, 경계가 뚜렷해지면 떼어내라.” 1~3편의 포트/어댑터 경계를 잘 그어 두면, 그 떼어내기가 훨씬 수월하다. 그게 이 시리즈를 하나로 꿰는 이유다.

참고

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다