본문 바로가기

Study

[내일배움캠프 TIL] MSA 총정리

728x90
반응형

1. MSA란 무엇인가?

Definition

하나의 큰 애플리케이션을 독립적으로 배포가 가능한 여러 개의 작은 서비스(Microservice) 조합으로 구축하는 아키텍처 스타일.

🆚 모놀리식(Monolithic) vs MSA

  • 모놀리식 (Monolithic): 모든 비즈니스 로직이 하나의 거대한 애플리케이션(Single 코드베이스)에 포함된 형태.
  • MSA (Microservices): 서비스별로 코드가 분리되어 있고, 각자 독립적인 데이터베이스(Database-per-Service)를 가짐. 서비스 간에는 REST API나 메시지 큐(gRPC, Kafka 등)를 통해 통신함.

2. 왜 MSA를 쓸까? (장단점)

👍 장점

  • 독립 배포 가능: 다른 서비스에 영향을 주지 않고 주문 서비스만 뚝딱 수정해서 배포할 수 있음.
  • 유연한 스케일 아웃: 이벤트 기간에 결제 서비스에만 트래픽이 몰리면, 그 서비스만 서버를 증설(Scale-out)하면 되므로 비용 효율적임.
  • 기술 스택의 자유: 회원 서비스는 Java/Spring, AI 추천 서비스는 Python/FastAPI로 만드는 등 서비스 특성에 맞는 언어와 DB 선택 가능.
  • 장애 격리: 추천 서비스 서버가 터져도, 로그인이나 결제 같은 핵심 기능은 정상 작동함.

👎 단점

  • 높은 복잡도: 서비스가 쪼개진 만큼 관리 포인트가 늘어나고, 모니터링 시스템(Prometheus, Grafana, Jaeger 등) 구축이 필수적임.
  • 데이터 정합성(Consistency) 문제: 트랜잭션이 여러 DB에 걸쳐 발생하므로 분산 트랜잭션 처리가 매우 까다로움 (Saga 패턴 등 필요).
  • 통신 오버헤드: 내부 메모리 호출이 아닌 네트워크(HTTP/gRPC)를 타고 통신하므로, 통신 지연(Latency)이 발생할 수 있음.
  • 테스트/디버깅 지옥: 하나의 기능을 테스트하려 해도 연관된 여러 서비스를 모두 띄워야 해서 로컬 테스트가 복잡함.

3. MSA 핵심 컴포넌트 패턴

MSA를 지탱하기 위해 필수로 들어가는 핵심 인프라 패턴들입니다.

① API Gateway

  • 역할: 클라이언트의 모든 요청을 단일 진입점으로 받아 적절한 마이크로서비스로 라우팅해주는 역할.
  • 주요 기능: 인증/인가(JWT 검증 등), 부하 분산(Load Balancing), 레이트 리밋(Rate Limiting).
  • 주요 기술: Spring Cloud Gateway

② Service Discovery (e.g. Netflix Eureka)

  • 역할: MSA 환경에서는 서비스 인스턴스가 동적으로 생성되고 삭제됨. 이 서비스들의 IP와 포트 번호를 실시간으로 등록하고 관리해주는 '전화번호부' 역할.
  • 💡 [중요] Eureka의 통신 메커니즘:
    • Eureka는 직접 데이터를 주고받는 '통신 도구'가 아닙니다.
    • 서비스들이 켜질 때 Eureka 서버에 자신의 IP와 포트를 등록(Register)해둡니다.
    • 서비스 A가 B에게 요청을 보낼 때, 먼저 Eureka에게 *"B 서비스 주소 어디 있어?"*라고 물어본 뒤(Discovery), 전달받은 주소로 REST API(HTTP/OpenFeign)나 gRPC를 이용해 진짜 통신을 주고받습니다.

4. MSA 소스코드 구조: 멀티모듈(모노레포) vs 멀티레포

"Git과 프로젝트 구조를 어떻게 가져갈 것인가?"에 대한 아키텍처 구현 전략입니다.

① 멀티모듈 (Multi-Module) / 모노레포 (Mono-Repo)

"하나의 Git 저장소, 하나의 프로젝트 안에서 폴더(모듈)만 쪼개기"

  • 구조: 하나의 Root 프로젝트(Gradle/Maven) 아래에 order-service, payment-service, common-core 같은 하위 모듈 폴더를 두고 개발하는 방식.
  • 👍 장점:
    • 코드 공유 고효율: 공통 에러 처리나 DTO(common 모듈)를 만들어서 다른 서비스 모듈들이 의존성 한 줄로 쉽게 가져다 쓸 수 있음.
    • 단일 Git 관리: 하나의 Git으로 관리하므로 히스토리 추적이 쉽고, 전체 시스템 변화를 한눈에 보기 편함.
  • 👎 단점:
    • 프로젝트가 무거워짐: 서비스가 늘어날수록 IDE(IntelliJ 등)가 로딩하고 빌드하는 데 시간이 오래 걸림.
    • 권한 분리 불가: Git 권한이 통째로 공유되므로, 다른 팀 코드를 실수로 수정할 위험이 있음.

② 멀티레포 (Multi-Repo)

"서비스마다 Git 저장소를 아예 따로 파기"

  • 구조: 주문 서비스 Git, 결제 서비스 Git이 완전히 독립되어 존재함. 프로젝트 창도 서비스마다 따로 띄워서 개발함.
  • 👍 장점:
    • 완벽한 독립성: 내 서비스 코드만 들어있으므로 가볍고 빌드가 매우 빠름. 다른 팀 코드를 실수로 건드릴 일이 전혀 없음.
    • 자유로운 기술 스택: 주문 서비스는 Java/Spring, 결제 서비스는 Node.js 등 Git 단위로 완전히 다른 환경을 구성하기 좋음.
  • 👎 단점:
    • 공통 코드 관리의 지옥: 여러 서비스에서 공통으로 쓰는 코드가 생기면, 각 Git마다 코드가 중복되거나 별도의 라이브러리(Jar) 패키지 서버를 파서 배포해야 하므로 관리가 까다로워짐.
    • 통합 테스트 불편: 여러 서비스를 넘나드는 기능을 로컬에서 테스트하려면, Git 저장소를 여러 개 clone 받아서 각각 따로 실행해야 하므로 번거롭습니다.

5. MSA의 고질병과 해결 전략 (핵심 키워드)

  • 분산 트랜잭션 (Saga 패턴): 2PC 방식은 가용성을 떨어뜨리므로 사용하지 않음. 각 서비스의 로컬 트랜잭션을 순차적으로 실행하고, 실패 시 역순으로 보상 트랜잭션(취소 작업)을 발동해 최종 일관성(Eventual Consistency)을 맞춤.
  • 이벤트 기반 아키텍처 (EDA): 서비스 간 강결합을 깨기 위해 Kafka, RabbitMQ 같은 메시지 브로커를 사이에 두고 이벤트(Event)를 발행/구독하는 방식으로 통신함.
  • 이벤트 발행의 보장 (Outbox / PDL): DB 저장은 성공했는데 카프카 전송은 실패하는 문제를 막기 위한 전략.
    • Outbox: 동일 DB 트랜잭션 묶음으로 임시 테이블에 이벤트를 저장해두고 CDC가 읽어가는 방식.
    • PDL (Producer Dead Letter): 발행 실패 시 고가용성 백업 큐로 우회시켜 DL 서버가 재처리하는 방식.
  • 장애 전파 방지 (Circuit Breaker): 연쇄 서버 다운을 막기 위해 타깃 서비스가 먹통이면 즉시 요청을 차단하고 폰백(Fallback) 메시지를 리턴함. (기술: Resilience4j)

6. 요약: 우리 팀에 맞는 아키텍처 선택 가이드

모놀리식 vs MSA

비교 항목 모놀리식 (Monolithic) 마이크로서비스 (MSA)

팀 규모 소규모 (~10명 내외) 대규모 (서비스별 독립 팀 운영)
비즈니스 복잡도 비교적 단순함 / 초기 스타트업 매우 복잡함 / 도메인이 계속 확장됨
초기 구축 속도 🚀 매우 빠름 🐌 인프라 세팅 등으로 느림
운영 비용 저렴함 비쌈 (DevOps 엔지니어 필수)

멀티모듈 vs 멀티레포

구분 멀티모듈 (Mono-Repo) 멀티레포 (Multi-Repo)

Git 저장소 개수 1개 서비스당 1개 (여러 개)
공통 코드 활용 🚀 매우 쉬움 (모듈 의존성 추가) 🐌 어려움 (중복 코드 혹은 내부 라이브러리 배포 필요)
팀별 권한 관리 불가능 (통째로 공유) 가능 (담당 서비스 Git만 권한 부여)
추천 상황 초기 MSA 시작 단계, 소규모 팀, 공통 도메인이 많을 때 마이크로서비스 규모가 커지고 팀이 완벽히 분리되었을 때

📌 결론

"도메인 복잡도가 임계점을 넘지 않았고 트래픽 변화가 크지 않다면 잘 짜인 모놀리식이 훨씬 유리하다. MSA로 가기로 심산했다면 초기에는 관리가 편한 **멀티모듈(모노레포)**로 시작해, 팀 규모와 서비스가 완전히 분리되는 시점에 멀티레포로 전환하는 전략이 권장된다."

반응형