개발 학습 실습실

이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.

공부 › 아키텍처와 운영 › 관측

분산 추적

요청 하나가 느린데 어느 서비스 탓인가

주문 요청 하나가 게이트웨이, 주문 서비스, 결제 서비스, 외부 결제사를 차례로 거칩니다. 로그는 서비스마다 따로 쌓이므로, 같은 요청의 로그를 묶을 공통 번호가 없으면 어디서 시간이 걸렸는지 찾기 어렵습니다.

문서·표준 대조 · W3C Trace Context 표준과 OpenTelemetry 문서

이 실습에 나오는 개념

분산 추적(Trace ID, Span)
하나의 요청이 여러 서비스를 거치며 처리되는 전체 경로를 추적하는 기술이다. 요청이 처음 들어올 때 고유한 추적 ID를 부여하고 서비스 사이의 호출마다 이를 함께 전달한다. 각 서비스의 처리 구간을 스팬이라 하며, 같은 추적 ID의 스팬을 모으면 어느 구간에서 시간이 걸렸는지 알 수 있다.
관측성(로그, 지표, 추적)
시스템의 외부 출력만으로 내부 상태를 파악할 수 있는 능력이다. 로그는 개별 사건의 기록, 지표(메트릭)는 요청 수나 응답 시간처럼 수치로 집계한 값, 추적은 하나의 요청이 여러 서비스를 거쳐 가는 경로와 구간별 소요 시간의 기록이다. 세 가지를 함께 갖춰야 문제를 감지하고 원인을 찾을 수 있다.
MDC
로그를 남길 때 현재 요청과 관련된 문맥 정보(요청 ID, 사용자 ID 등)를 자동으로 함께 출력하게 해 주는 로깅 기능이다. 스레드별로 값을 보관하며, 요청이 시작될 때 값을 넣어 두면 그 요청을 처리하는 스레드가 남기는 모든 로그에 같은 값이 찍힌다. 여러 요청의 로그가 섞여 있어도 한 요청의 로그만 골라 볼 수 있다.
APM
애플리케이션의 성능을 모니터링하는 도구다. 요청별 응답 시간, 어느 메서드나 쿼리에서 시간이 걸렸는지, 오류 발생 현황 등을 수집해 보여 준다. 자바에서는 주로 에이전트 방식으로 코드 수정 없이 적용한다. Pinpoint, Scouter, Datadog 등이 있다.
모놀리식과 MSA(마이크로서비스)
모놀리식은 모든 기능을 하나의 애플리케이션으로 만들어 함께 배포하는 구조다. MSA는 기능별로 작은 서비스로 나눠 각각 독립적으로 개발, 배포, 확장하는 구조다. MSA는 서비스별로 따로 배포하고 확장할 수 있고 장애가 격리되지만, 서비스 간 통신, 데이터 일관성, 운영의 복잡도가 크게 늘어난다.

이렇게 바꿔 보세요

처음 설정으로 실행하면

  1. 요청이 게이트웨이에 도착합니다. 추적 번호가 없는 요청이므로 새 Trace ID(4bf92f35…)를 만듭니다. 이 요청이 끝날 때까지 이 번호가 따라다닙니다. 게이트웨이의 처리 구간이 첫 번째 스팬입니다.
  2. 게이트웨이가 주문 서비스를 호출할 때 HTTP 헤더에 Trace ID와 자기 스팬 ID를 실어 보냅니다. 주문 서비스는 같은 Trace ID를 이어받고, 자신의 구간을 새 스팬으로 기록합니다(부모는 게이트웨이의 스팬).
  3. 주문 서비스가 DB를 조회합니다(30ms). 이 쿼리도 하나의 스팬으로 기록됩니다.
  4. 주문 서비스가 결제 서비스를 호출합니다. 이번에도 헤더로 Trace ID가 전달됩니다. 로그를 남길 때마다 MDC에 들어 있는 Trace ID가 자동으로 함께 찍힙니다.
  5. 결제 서비스가 외부 결제사 API를 호출합니다(2000ms). 응답이 돌아오면 거꾸로 결제 서비스, 주문 서비스, 게이트웨이 순으로 스팬이 닫힙니다. 전체 2095ms.
  6. 추적 시스템(Zipkin, Tempo 등)에서 Trace ID 하나로 조회하면 다섯 구간이 시간 축 위에 계단 모양으로 그려집니다. 안쪽 호출을 뺀 자체 시간이 가장 긴 구간은 "외부 결제사 API"입니다. 어디가 느린지 바로 보입니다.

실행 결과

코드

// build.gradle: Micrometer Tracing
implementation 'io.micrometer:micrometer-tracing-bridge-otel'

# 서비스끼리 호출할 때 자동으로 붙는 헤더 (W3C Trace Context)
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
#               └─ trace id (요청 전체에서 동일)      └─ span id (구간마다 다름)

# 로그 패턴에 추적 번호를 넣는다 (MDC에서 꺼냄)
logging.pattern.level: "%5p [%X{traceId:-},%X{spanId:-}]"

이 모형의 전제

서비스 네 개를 차례로 호출하는 단순한 구조이고 시간은 예시 값입니다. Trace ID와 스팬, 헤더로 전파하는 방식은 W3C Trace Context 표준과 OpenTelemetry, Micrometer Tracing 문서의 설명을 따랐습니다. 실제로는 모든 요청을 기록하지 않고 일부만 표본으로 수집하는 경우가 많습니다.

앞 실습: 평균과 백분위 · 다음 실습: merge와 rebase

이 실습에 나오는 개념

이 실습에서 보는 것

설정

코드


      
    

그림

실행 비교

이렇게 바꿔 보세요