서비스를 9개로 쪼갰더니 장애 하나 찾는 데 더 오래 걸렸다
MSA로 나누면서 생긴 대가 - 요청 하나가 여러 서비스를 거치면서 원인 분석이 흩어졌다. OpenTelemetry로 전 구간을 하나의 트레이스로 잇고 Prometheus·Tempo·OpenSearch·Grafana로 모은 과정.
문제: 서비스를 쪼갠 대가는 "어디서 실패했는지"를 잃는 것이었다
모놀리식일 때는 요청이 실패하면 로그 하나만 열면 됐다. 함수 호출 스택이 프로세스 하나 안에 있었으니까. MSA로 쪼개고 나니 요청 하나가 게이트웨이 → API 서버 → 큐 → AI 추론 → 후처리를 거치는 여러 홉짜리 여정이 됐다. 실패가 나면 "어느 서비스에서, 어느 단계에서 문제가 생겼는가"를 알기 위해 서비스별로 흩어진 로그를 각각 열어 시간대를 맞춰봐야 했다.
서비스가 9개면 이 조합은 9배로 늘어난다. 배포 단위를 쪼갠 이득(재배포 10건→1건, 2편 참고)을 얻은 대신, 장애 원인 분석이 더 오래 걸릴 수 있다는 대가를 그대로 받아들일 수는 없었다.
시도한 것: 계측 표준을 하나로 통일하기
핵심 결정은 "각 서비스가 알아서 로그를 남기게 두지 않는다"는 것이었다. **OpenTelemetry(OTel)**를 계측 표준으로 채택해서, CI/CD 파이프라인부터 게이트웨이, 애플리케이션 파드, DB 호출까지 전 구간에 동일한 방식으로 계측을 심었다.
[ Bitbucket → Argo Workflows → ArgoCD ] ← CI/CD 단계
│ OTel 계측
▼
[ Envoy Gateway ] ── 요청 진입, trace 시작
│
▼
[ API 서버 ] → [ RabbitMQ ] → [ AI 추론 ] → [ 후처리 ]
│ 각 서비스가 같은 trace ID를 이어받아 span 기록
▼
┌─────┴─────┬──────────┐
▼ ▼ ▼
[Prometheus] [Tempo] [OpenSearch]
메트릭 분산 트레이스 로그
└─────┬─────┴──────────┘
▼
[ Grafana ] ← 하나의 화면에서 통합 조회
- Prometheus: 서비스별 요청 수·에러율·지연시간 같은 시계열 메트릭.
- Tempo: 분산 트레이스 - 요청 하나가 게이트웨이부터 DB까지 어떤 경로로, 각 구간에서 얼마나 걸렸는지를 하나의 trace ID로 이어 기록.
- OpenSearch: 각 서비스가 남기는 로그를 모아 검색 가능한 형태로 저장.
- Grafana: 위 세 가지를 한 화면에서 조회 - 메트릭에서 이상 징후를 보고, 해당 시간대 trace로 어느 서비스에서 지연이 발생했는지 좁히고, 그 서비스의 로그를 trace ID로 바로 필터링해서 원인을 확인하는 흐름이 가능해진다.
이전 방식과 가장 크게 다른 지점은 trace ID로 서비스 경계를 넘어 요청을 추적할 수 있다는 것이다. 예전이라면 "API 서버 로그에서 요청이 들어온 시각"과 "AI 추론 로그에서 그 즈음 처리된 작업"을 시간으로 짐작해서 연결해야 했다. 지금은 같은 trace ID로 두 로그가 이미 이어져 있다.
결과
정량적인 "장애 원인분석 시간이 몇 % 줄었다" 같은 수치는 아직 제대로 측정해두지 못했다 - 이 부분은 정성적인 확인에 머물러 있다. 하지만 구조적으로 확실해진 건, 요청 하나를 게이트웨이부터 DB까지 trace ID 하나로 따라갈 수 있게 됐다는 것이다. 서비스가 9개로 늘어난 만큼 원인 분석이 더 오래 걸릴 위험을 계측 표준화로 상쇄한 셈이다.
다음 단계는 이 관측 스택을 근거로 실제 MTTR(장애 감지부터 원인 파악까지 걸리는 시간)을 재는 것이다. 지금은 "trace를 따라갈 수 있다"는 구조까지는 만들어뒀고, 이걸 실제 장애 대응 시나리오에서 얼마나 단축시키는지는 다음에 장애를 주입해보고 숫자로 확인할 부분이다.