MSA 패턴, 분리의 이득과 운영 비용
MSA는 독립 배포, 독립 확장, 장애 격리를 얻기 위해 서비스를 나누는 아키텍처 패턴의 집합이다. 다만 API Gateway, Service Mesh, Circuit Breaker, Saga, Outbox 같은 주변 패턴까지 함께 운영해야 하므로 도입 기준과 실패 조건을 함께 봐야 한다.
Script Companion
오디오와 함께 스크립트 보기
- 01
MSA를 볼 때 먼저 붙잡아야 할 점은, 이것이 단순히 서비스를 작게 쪼개는 방식이 아니라는 것이다. 문서의 핵심은 독립 배포, 독립 확장, 장애 격리라는 이득과, 분산 시스템이 가져오는 운영 복잡성을 함께 계산하라는 데 있다. BackOps 엔지니어에게 MSA가 중요한 이유도 여기에 있다. 서비스 간 의존 관계를 이해하고, 장애가 어느 다운스트림으로 번지는지 추적해야 하기 때문이다. NestJS 역시 @nestjs/microservices 모듈로 TCP, Redis, RabbitMQ 기반 마이크로서비스 전환을 지원한다.
- 02
모놀리스는 초기에 꽤 강하다. 모든 모듈이 같은 프로세스에서 실행되기 때문에 함수 호출이 네트워크 호출보다 빠르고, 주문, 결제, 재고를 하나의 DB 트랜잭션으로 묶을 수 있으며, 로컬에서 전체 흐름을 디버깅하기도 쉽다. 문제는 규모가 커졌을 때 변경 단위, 확장 단위, 장애 단위가 모두 애플리케이션 전체로 고정된다는 점이다. 결제 로직만 바꿔도 전체를 다시 배포해야 하고, 주문 조회 트래픽만 늘어도 전체 애플리케이션을 복제해야 한다. 한 모듈의 메모리 누수도 프로세스 전체를 죽일 수 있다.
- 03
MSA는 이 한계를 서비스 분리와 중앙 통제 구조로 우회한다. 비즈니스 경계별로 배포 단위를 나누고, 각 서비스가 자기 데이터 저장소를 소유하게 만든 뒤, 외부 진입은 API Gateway로 모은다. 내부 서비스 간 정책은 Service Mesh, Circuit Breaker, Saga, Outbox 같은 패턴으로 제어한다. 여기서 Database per Service는 선택이 아니라 핵심 전제 조건이다. 공유 DB를 쓰면 독립 배포와 데이터 소유권이 흐려진다. 반대로 주문과 사용자 정보를 한 번에 조인할 수 없으므로, API 호출로 데이터를 모아야 하는 비용도 받아들여야 한다.
- 04
도입 판단은 MSA 허가서가 아니라 반례를 찾는 질문지에 가깝다. 팀이 10명 이하이고 도메인 경계가 불명확하며 배포가 주 1회 이하라면 모놀리스가 더 자연스럽다. 팀이 30명 이상이고, 도메인 경계가 명확하고, 일 단위 독립 배포와 높은 DevOps 성숙도가 필요할 때 MSA의 명분이 생긴다. 실무에서는 모놀리식 먼저, 경계가 보이면 분리가 안전하다. 분리 후보는 배포 주기가 다르고, 트래픽 피크가 다르고, 장애 전파를 막아야 하는 조건을 동시에 만족할수록 우선순위가 높다.
- 05
비용도 숫자로 봐야 한다. 문서에서는 함수 호출이 약 1마이크로초인 반면 HTTP 호출은 약 1밀리초로, 약 1,000배 차이가 난다고 짚는다. ECS 서비스가 나뉘면 서비스마다 Task Definition, CloudWatch 대시보드, ALB Target Group 같은 운영 리소스가 늘어난다. 분산 추적이 없으면 장애 원인 파악 시간도 단일 로그 스트림의 평균 약 15분에서 45분에서 2시간까지 늘어날 수 있다. Twilio Segment 사례도 같은 결론을 보여준다. 140개가 넘는 서비스를 통합한 이유는 MSA 금지가 아니라, 분리 이득을 측정할 수 없으면 통합이 더 빠를 수 있다는 점이었다.
- 06
API Gateway는 클라이언트와 마이크로서비스 사이의 단일 진입점이다. Gateway가 없다면 클라이언트는 서비스별 주소를 직접 알아야 하고, 서비스 주소가 바뀔 때마다 클라이언트 코드도 바뀐다. Gateway는 라우팅, 인증과 인가, Rate Limiting, 요청과 응답 변환을 한곳에서 맡는다. 각 서비스가 JWT 검증을 중복 구현하지 않아도 되는 것도 이점이다. 단일 Gateway가 모든 클라이언트를 만족시키기 어려워질 때는 BFF, Backend for Frontend 패턴을 쓴다. 모바일 BFF는 응답을 압축하고 최소화하며, 웹 BFF는 여러 서비스 데이터를 집계해 반환한다.
- 07
API Gateway도 깨지는 조건이 있다. AWS API Gateway 기준으로 계정 초당 최대 요청 수는 리전당 10,000 req/s이고, 버스트 한도는 5,000 req이다. 한도를 넘으면 429 Too Many Requests가 반환된다. 중요한 점은 개별 API 평균 RPS가 아니라 계정과 리전 전체 RPS 합계를 봐야 한다는 것이다. P99 지연이 1초를 넘으면 CloudWatch에서 Latency와 IntegrationLatency를 분리해 확인한다. Latency에서 IntegrationLatency를 뺀 값이 크면 Gateway 오버헤드이고, IntegrationLatency가 크면 백엔드 병목이다. dev와 prod를 단일 스테이지에 섞거나, 캐싱 없이 모든 GET 요청을 백엔드로 보내거나, WAF 없이 공개 엔드포인트를 운영하는 구조도 단일 장애점이 된다.
- 08
Service Mesh는 내부 서비스 간 트래픽, 즉 East-West 트래픽을 다루는 인프라 레이어다. Istio의 핵심은 Sidecar Proxy 패턴이다. Kubernetes Pod 안에서 서비스 컨테이너와 Envoy 프록시 컨테이너가 나란히 실행되고, 모든 인바운드와 아웃바운드 트래픽이 Envoy를 지난다. 서비스 코드는 localhost로 통신한다고 생각하지만 실제 트래픽 제어는 Envoy가 맡는다. Istiod라는 Control Plane은 각 Envoy에 xDS 프로토콜로 규칙을 전달하고, Envoy들이 Data Plane으로 실제 트래픽을 처리한다.
- 09
Service Mesh가 주는 가치는 세 가지로 정리된다. 첫째, mTLS로 서비스 간 통신을 코드 수정 없이 TLS 암호화하고, Istiod가 인증서를 자동 발급하고 갱신한다. 둘째, 카나리 배포, A/B 테스트, 서킷 브레이킹, 재시도 정책을 Control Plane 설정으로 제어한다. 셋째, 지연, 오류율, 처리량 같은 메트릭을 자동 수집하고 Prometheus, Jaeger, Kiali와 연동한다. 다만 소규모 팀에는 오버엔지니어링이 될 수 있다. 문서는 AWS ALB, 서비스별 로깅, X-Ray 분산 추적으로 시작하고, 서비스가 10개를 넘어설 때 Service Mesh를 검토하는 접근을 현실적인 대안으로 제시한다.
- 10
Edge Computing은 클라이언트와 API Gateway 사이에 놓이는 전처리 계층이다. 서비스 자체의 비즈니스 로직을 건드리지 않으면서 인증 토큰 검증, 지역 라우팅, A/B 테스트 트래픽 분기 같은 공통 관심사를 엣지에서 처리한다. AWS에서는 CloudFront Functions와 Lambda@Edge가 대표 옵션이다. CloudFront는 600개 이상의 PoP와 13개 리전 엣지 캐시를 제공한다. CloudFront Functions는 모든 엣지 로케이션에서 실행되어 URL 재작성과 헤더 조작처럼 짧은 작업에 맞고, 보통 1ms 미만 오버헤드와 수백만 RPS 확장을 목표 용도로 설명된다. 네트워크, 파일 시스템, 환경변수 접근이 필요한 로직은 Lambda@Edge 쪽이 맞다.
- 11
Circuit Breaker는 한 서비스가 응답 불능일 때 무한 대기하지 않고 빠르게 실패시켜 전체 시스템을 보호하는 패턴이다. 단순히 실패하면 에러를 반환하는 장치가 아니라, 복구 시점을 탐지하기 위해 Closed, Open, Half-Open 상태를 전환한다. Open 상태에서 영구 차단하면 서비스가 복구되어도 트래픽을 받지 못하므로, Half-Open으로 조심스럽게 복구를 확인한다. ECS 환경에서는 Circuit Breaker가 OPEN 상태임을 헬스체크 엔드포인트에 반영해 자가 회복 구조를 만들 수 있다. ECS는 헬스체크 실패 시 Task를 교체하고, ALB는 UNHEALTHY 인스턴스로의 트래픽을 차단한다.
- 12
Circuit Breaker 설정은 너무 민감해도, 너무 둔감해도 역효과가 난다. opossum 기준 권장값은 timeout 3,000ms, errorThresholdPercentage 50, resetTimeout 30,000ms, volumeThreshold 5다. timeout은 서비스 SLA P99 응답 시간의 3배에서 5배로 잡고, 최소 5회 요청 이후부터 통계를 적용한다. resetTimeout 뒤 Half-Open이 되었지만 서비스가 아직 회복되지 않았다면 첫 요청 실패로 즉시 재Open된다. 이때는 실패할 때마다 resetTimeout을 2배씩 늘리는 지수 백오프를 적용해 불필요한 탐색 요청을 줄인다. 설정값은 장애를 감추기 위한 숫자가 아니라, 실패 전파를 제한하면서 복구 가능성을 확인하는 기준이다.
- 13
CQRS는 쓰기와 읽기를 분리하는 패턴이다. 주문을 처리하는 Command와 메뉴를 보여주는 Query가 서로 다른 책임을 갖는 것처럼, 복잡한 규칙이 필요한 쓰기 모델과 빠른 조회가 필요한 읽기 모델을 나눈다. MSA에서는 Query Side가 다른 서비스의 이벤트를 수신해 자기만의 읽기 모델을 유지하고, AWS SNS/SQS가 이벤트 전달의 신뢰성을 보강한다. 이 구조는 순환 의존 문제를 줄이는 실마리도 된다. 주문 서비스가 사용자 서비스를 호출하고, 사용자 서비스가 주문 이력을 위해 다시 주문 서비스를 호출하는 동기 체인은 데드락을 만들 수 있다. 주문 이력은 주문 서비스가 소유하고, 사용자 서비스는 필요한 주문 데이터를 이벤트로 받아 자체 DB에 복제하는 방향이 더 안전하다.
- 14
Saga와 Outbox는 분산 트랜잭션 일관성을 다룬다. 모놀리스에서는 하나의 DB 트랜잭션으로 출금과 입금을 묶을 수 있지만, MSA에서는 A 계좌 서비스와 B 계좌 서비스가 다른 DB를 쓴다. Saga는 이 작업을 일련의 로컬 트랜잭션과 보상 트랜잭션으로 나눈다. Choreography는 각 서비스가 이벤트를 발행하고 구독하는 방식이고, Orchestration은 중앙 Orchestrator가 흐름을 제어하는 방식이다. 서비스 3개에서 4개 이내의 단순 흐름은 Choreography가 간단하고, 서비스 5개 이상이거나 조건부 분기와 타임아웃이 많으면 Orchestration이 디버깅에 유리하다.
- 15
Outbox는 DB 저장과 이벤트 발행을 하나의 로컬 트랜잭션으로 묶어, DB는 커밋됐는데 SQS 발행이 실패하는 상황을 막는다. Saga가 최종 일관성과 보상 트랜잭션을 제공한다면, Outbox는 At-Least-Once 이벤트 전달을 전제로 메시지 유실을 줄인다. 엣지 케이스도 중요하다. 보상 트랜잭션이 실패하면 지수 백오프 재시도와 Dead Letter Queue 이관, 운영팀 알림이 필요하다. 이벤트 순서가 뒤집힐 수 있으면 페이로드에 버전 번호나 타임스탬프를 넣고 멱등성 키를 확인해야 한다. AWS Step Functions 표준 워크플로우가 최대 1년 실행 가능하다는 점은 개별 단계가 무제한 대기해도 된다는 뜻이 아니므로, 단계별 HeartbeatSeconds와 TimeoutSeconds를 설정해야 한다.
- 16
마지막으로 SQS 중복 처리는 MSA에서 자주 만나는 실패 모드다. AWS SQS는 At-Least-Once Delivery를 보장하므로, 네트워크 이슈나 처리 시간 초과, ECS 태스크 재시작 뒤 visibility timeout 만료로 같은 메시지가 다시 전달될 수 있다. SQS FIFO 큐는 MessageDeduplicationId로 5분 내 중복 메시지를 제거하고, 기본 FIFO 큐는 파티션당 API action별 300 TPS, batching 사용 시 3,000 messages/s까지 처리한다. 하지만 FIFO deduplication은 소비자 로직의 영구 멱등성을 대체하지 않는다. 운영자 재처리, DLQ redrive, 5분을 넘긴 재전달까지 고려하면 ProcessedEvent 같은 저장소 기반 멱등성 키를 유지해야 한다. 정리하면 MSA는 마이크로서비스, API Gateway, Service Mesh, Edge Computing, Circuit Breaker, CQRS, Saga, Outbox를 함께 보는 패턴 집합이고, 작은 팀에서는 모놀리식 먼저, 경계가 보이면 분리가 현실적인 전략이다.
같은 레이어
L9에서 이어 듣기
- 설계 원칙을 운영 가능한 코드로 잇기 길이 미정
- Clean Architecture의 의존성 규칙 길이 미정
- DDD 기본기: 도메인 언어와 경계 설계 길이 미정
- Twelve-Factor App 운영 원칙 길이 미정
- CAP과 일관성으로 보는 분산 시스템 선택 길이 미정
- Saga Pattern: 로컬 커밋과 역순 보상 길이 미정
- CQRS와 이벤트 소싱의 운영 경계 길이 미정
- TDD와 테스트 피라미드로 설계하는 테스트 전략 길이 미정
- 대규모 웹 크롤러의 큐, 정중함, 중복 제거 길이 미정
- API 계약으로 안전하게 서비스 경계를 진화시키기 길이 미정
- URL Shortener와 Rate Limiter로 보는 시스템 디자인 길이 미정