← all posts
DEV 2026.05.02 · 15 min read Intermediate

MSA 운영의 핵심은 관찰 가능성이다

분산 추적의 Trace ID부터 RED 메트릭, 배포 전략, 카스케이드 장애 방지까지 — MSA를 운영 가능한 시스템으로 만드는 설계 철학을 추적한다.


마이크로서비스 아키텍처는 독립 배포와 확장성을 약속한다. 하지만 그 대가로 시스템이 “보이지 않는” 곳에서 조용히 무너지기 시작한다. 결제 서비스 하나가 느려지면 왜 주문 서비스 전체가 멈추는가? 그리고 그 사실을 언제, 어떻게 알 수 있는가?

흩어진 시스템을 묶는 실 — Trace ID

모놀리식 애플리케이션에서는 스택 트레이스 한 줄로 요청 흐름을 볼 수 있다. MSA에서는 같은 요청이 10개 서비스를 거치며 로그가 10개 서버에 흩어진다.

분산 추적은 이 문제를 Trace ID라는 단일 식별자로 해결한다. 요청이 API Gateway에서 시작되는 순간 UUID가 생성되고, 이후 모든 서비스 호출에 HTTP 헤더(traceparent)로 전파된다. 각 서비스는 이 Trace ID를 받아 자신의 작업 단위(Span)를 기록하고, 결과적으로 하나의 요청이 어느 서비스에서 얼마나 걸렸는지 타임라인으로 재구성된다.

Trace ID: 550e8400-e29b-41d4-a716-446655440000
├─ createOrder      [0ms - 2500ms]   OrderService
│  ├─ payment.process [50ms - 1500ms]  PaymentService
│  │  └─ gateway.call  [100ms - 1400ms] ← 병목!
│  └─ inventory.update [1500ms - 2200ms] InventoryService

이 구조가 있어야 “결제가 느리다”는 불평을 받았을 때 payment.gateway.call이 1300ms를 잡아먹고 있다는 사실을 30초 안에 알 수 있다. 없으면 수십 분이 걸린다.

OpenTelemetry는 이 추적 계층을 벤더 중립적으로 표준화한다. 계측 코드 한 벌로 Zipkin, Jaeger, Datadog 어디에나 연결된다. Spring Boot에서는 micrometer-tracing-bridge-otel 의존성 하나로 HTTP, DB, 메시지 브로커 호출이 자동 계측된다.

샘플링 전략

프로덕션에서 모든 요청을 추적하면 저장소 비용이 폭발한다. 초당 10,000 요청 기준 100% 샘플링은 하루 수십 GB다. parentBased(traceIdRatioBased(0.05))처럼 진입점에서 5%만 샘플링하면 오버헤드 1% 미만으로 유지할 수 있다. 에러가 발생한 Trace는 100% 보존하는 Tail-based 샘플링은 가장 정밀하지만 Collector 비용이 높다.

숫자로 시스템의 맥박을 읽는다 — RED 방법론

로그는 사건의 기록이다. 메트릭은 시스템의 맥박이다. MSA에서 수십 개 서비스를 로그만으로 모니터링하면 저장소가 먼저 터진다.

RED 방법론은 세 숫자로 서비스 상태를 요약한다.

  • Rate: 초당 처리 요청 수. 시스템 부하 수준을 나타낸다.
  • Errors: 에러율(%). 장애를 감지하는 첫 번째 신호다.
  • Duration: P50/P95/P99 응답시간. 성능 저하를 정량화한다.
Timer.builder("order.creation.duration")
    .publishPercentiles(0.5, 0.95, 0.99)
    .register(meterRegistry);

이 세 숫자만 있으면 대부분의 이상 징후를 패턴으로 읽을 수 있다. Rate가 정상인데 Errors가 갑자기 5%로 올라가면 새 배포에서 버그가 들어온 것이다. Errors는 정상인데 Duration이 2배가 됐다면 데이터베이스 성능 저하를 의심할 수 있다.

Prometheus가 메트릭을 수집하고, Grafana가 시각화하고, AlertManager가 에러율이 임계값을 넘으면 Slack으로 알림을 보낸다. 메트릭 저장소는 로그(월 수백 GB)에 비해 압도적으로 작다 — 같은 규모에서 월 10-50달러 수준이다.

배포는 “언제”가 아니라 “얼마나 안전하게”다

전통적 배포는 모든 서버를 동시에 새 버전으로 교체한다. MSA에서 이 방식은 버그 하나가 전체 사용자에게 즉시 전달된다는 의미다.

Blue/Green 배포는 이전 버전(Blue)을 유지한 채 새 버전(Green)을 준비하고, 준비가 완료되면 로드밸런서를 전환한다. 문제 발생 시 5초 안에 Blue로 돌아올 수 있다. 단점은 인프라를 2배 준비해야 한다는 것이다.

Canary 배포는 더 보수적이다. 트래픽의 1%를 새 버전으로 먼저 보내고, 에러율과 응답시간이 정상이면 5% → 20% → 100%로 점진적으로 확대한다. PaymentGateway.call 지연이 10% 트래픽에서 감지됐다면, 전체 사용자가 아닌 10%만 영향을 받는다.

Feature Flag는 한 단계 더 나아간다. 코드는 이미 배포됐지만 기능은 꺼져 있다. 플래그 하나를 끄면 코드 롤백 없이 모든 사용자가 즉시 이전 동작으로 돌아온다. 배포와 활성화를 완전히 분리할 수 있어 A/B 테스트에도 그대로 쓸 수 있다.

장애는 전파된다 — 격리가 설계다

MSA의 가장 위험한 특성은 장애 전파다. PaymentService가 응답시간 5초로 느려지면 OrderService 스레드가 모두 여기서 대기하게 된다. 스레드 풀이 다 차면 OrderService도 응답을 못 한다. 연쇄적으로 API Gateway, 프론트엔드까지 다운된다. 하나의 서비스 장애가 전체 시스템을 무너뜨리는 카스케이드 장애다.

세 가지 패턴이 이를 막는다.

Circuit Breaker는 전기 회로의 차단기와 같다. 에러율이 50%를 넘으면 해당 서비스 호출을 즉시 차단(OPEN)하고, 30초 후 소량의 테스트 호출을 허용(HALF_OPEN)한다. 회복이 확인되면 다시 정상(CLOSED)으로 전환된다. 핵심은 “느린 서비스를 계속 기다리지 않는다”는 것이다.

Bulkhead는 스레드 풀을 서비스별로 격리한다. OrderService 전체 스레드 50개 중 PaymentService 호출용 20개를 별도로 분리하면, PaymentService가 장애 나도 나머지 30개 스레드는 다른 작업을 계속 처리할 수 있다.

Saga 패턴은 분산 트랜잭션을 다룬다. 주문 생성 → 결제 → 재고 업데이트가 순서대로 진행되다가 재고 단계에서 실패하면, 앞서 완료된 결제를 취소하는 보상 트랜잭션이 역순으로 실행된다. ACID 트랜잭션이 아니라 “최종 일관성”을 보장하지만, MSA에서 분산 롤백을 구현하는 현실적인 방법이다.

트레이드오프

이 패턴들은 복잡성을 더한다. Circuit Breaker는 “즉시 실패”를 의미하므로 Fallback 로직이 필요하다. Bulkhead는 메모리를 더 쓴다. Saga의 보상 로직은 비즈니스 로직만큼 복잡해질 수 있다. 핵심 기능에만 선별적으로 적용해야 한다.

서비스 의존성은 단방향이어야 한다

순환 의존성은 MSA에서 조용한 시한폭탄이다. OrderService가 PaymentService를 호출하고, PaymentService가 다시 OrderService를 호출하면? 두 서비스가 서로를 기다리며 스레드를 잡아먹는 분산 데드락이 발생할 수 있다.

해결은 구조적이다. 직접 호출 대신 이벤트를 쓴다. OrderService는 “주문 생성됨” 이벤트를 메시지 큐에 발행하고, PaymentService는 이를 구독해서 처리한다. 두 서비스가 서로를 알 필요가 없다. 의존 방향이 항상 단방향이고, 그 사이에 메시지 큐가 버퍼 역할을 한다.

DFS 기반 순환 감지를 CI/CD 파이프라인에 넣어두면 의존 그래프에 사이클이 생기는 순간 빌드가 실패한다. 운영 중에 발견하는 것보다 훨씬 낫다.

정리

  • 관찰 가능성은 선택이 아니다. Trace ID로 요청 흐름을 추적하고, RED 메트릭으로 맥박을 읽고, 구조화 로그로 필드 기반 검색이 가능해야 비로소 MSA를 “운영”할 수 있다.
  • 배포는 안전하게 느리게. Canary + Feature Flag 조합으로 새 버전이 실제 트래픽에서 안전한지 검증한 뒤 확대한다.
  • 장애는 격리해야 전파되지 않는다. Circuit Breaker와 Bulkhead 없는 MSA는 단일 장애 지점이 전체를 무너뜨리는 구조다.
  • 분산 트랜잭션은 Saga로. ACID는 포기하고 보상 트랜잭션으로 최종 일관성을 보장한다.