이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- Distributed Tracing은 로그와 메트릭으로는 부족한 어떤 질문에 답하는가?
- Trace, Span, Span Attribute를 Spring 백엔드 장애 분석에서 어떻게 읽어야 하는가?
- Sampling과 span 설계를 잘못하면 어떤 문제가 생기는가?
개요
Distributed Tracing은 하나의 요청이 여러 서비스와 의존성을 지나가는 경로를 기록하는 관측 신호다.
Trace는 요청 전체 경로이고, span은 그 안의 한 작업 구간이다.
예를 들어 주문 생성 요청은 controller, service, DB query, Redis, 외부 결제 API 호출 span으로 나뉠 수 있다.
메트릭이 “latency가 증가했다”를 보여 준다면 tracing은 “어느 구간이 느려졌는가”를 보여 준다.
Trace와 Span
Trace는 하나의 요청 단위다.
Span은 trace 안에서 측정 가능한 작업 단위다.
trace order-create
span HTTP POST /api/orders
span OrderService.create
span SELECT product
span INSERT order
span POST payment-api각 span은 시작 시간, 종료 시간, duration, status, attribute를 가진다.
장애 분석에서는 duration이 긴 span, error status가 붙은 span, retry가 반복된 span을 먼저 본다.
Spring에서의 전파
서비스 간 trace가 이어지려면 trace context가 HTTP header로 전달되어야 한다.
W3C Trace Context에서는 traceparent header가 대표적이다.
Spring Boot 관측 설정과 HTTP client instrumentation이 맞으면 inbound 요청에서 시작된 trace가 outbound 호출까지 이어진다.
직접 만든 HTTP client나 message publisher가 context를 전달하지 않으면 trace가 끊긴다.
비동기 처리에서도 context 전파를 확인해야 한다.
Span Attribute
Span attribute는 분석에 필요한 제한된 정보를 담는다.
http.method=POST
http.route=/api/orders
db.system=mysql
db.operation=SELECT
external.service=payment-api
app.version=1.8.3Attribute도 metric label처럼 cardinality를 조심해야 한다.
order id, user email, raw SQL 전체를 넣으면 저장 비용과 보안 문제가 생길 수 있다.
고유 요청 정보는 log field나 event로 제한적으로 남기는 편이 낫다.
Sampling
모든 요청을 tracing하면 비용이 커질 수 있다.
그래서 sampling을 둔다.
하지만 sampling이 너무 낮으면 장애 요청 trace가 남지 않는다.
오류 요청은 더 높은 비율로 보존하거나 tail sampling을 검토할 수 있다.
트래픽이 낮은 핵심 API는 sampling 기준을 다르게 잡아야 할 수 있다.
운영 체크리스트
- HTTP inbound와 outbound 호출에 trace context가 전파되는가?
- 주요 DB, Redis, 외부 API 호출이 span으로 보이는가?
- span 이름이 endpoint와 작업 의미를 설명하는가?
- error span이 status와 exception 정보를 남기는가?
- sampling 비율이 장애 분석에 충분한가?
- span attribute에 고유 식별자나 민감 정보가 들어가지 않는가?
- trace id가 로그 field와 연결되는가?
장애 신호
- 서비스 A trace에서 서비스 B 호출 이후 trace가 끊긴다.
- latency는 증가했지만 느린 span이 너무 큰 이름 하나로만 보인다.
- 모든 DB query가 같은 span 이름이라 어떤 작업이 느린지 모른다.
- error 요청 trace가 sampling 때문에 남지 않는다.
- span attribute에 user email이나 token 일부가 들어간다.
- trace id는 있는데 로그에서 같은 trace id를 찾을 수 없다.
안전한 완화 조치
Trace가 끊기면 context propagation이 빠진 지점을 찾는다.
HTTP client, async executor, message publisher, scheduled job을 순서대로 본다.
Sampling이 낮아 장애 요청을 못 본다면 오류 요청 보존 정책을 조정한다.
Span을 너무 세밀하게 늘리면 비용과 noise가 커지므로 핵심 경로부터 instrument한다.
민감 attribute가 들어갔다면 수집 중단, 삭제, 접근 범위 확인을 진행한다.
인프라 담당자와 공유할 자료
증상: 주문 생성 p95 latency 증가
trace_id: 4bf92f3577b34da6a3ce929d0e0e4736
root span: POST /api/orders, 2400ms
slow span: POST payment-api, 1900ms
service version: order-api 1.8.3-abc1234
log correlation_id: c-7f1
의심: payment-api 응답 지연 또는 retry 증가Tracing 자료는 trace id, root span, 느린 span, error span, 관련 로그 id를 함께 제공해야 한다.
실전 팁
- Trace는 요청 경로와 구간별 시간을 보는 도구다.
- Span 이름은 사람이 읽고 원인을 좁힐 수 있게 짓는다.
- Error 요청이 sampling에서 빠지지 않게 한다.
- Trace id를 log field에 포함한다.
- 모든 코드를 span으로 감싸기보다 핵심 dependency 호출부터 시작한다.
위험 신호!
- trace가 서비스 경계에서 끊긴다.
- span 이름이 모두
execute처럼 의미가 없다. - sampling 비율이 낮아 장애 요청이 남지 않는다.
- attribute에 raw SQL, token, email을 넣는다.
- trace만 보고 전체 영향 규모를 판단한다.
확인 질문
확인 질문
- Tracing이 Metrics와 다른 점은 무엇인가?
- Metrics는 전체 규모와 추세를 보여 주고, tracing은 개별 요청이 지나간 경로와 구간별 시간을 보여 준다.
- Span이 너무 크면 어떤 문제가 생기는가?
- 느린 구간을 세분화할 수 없어 어느 dependency나 작업이 병목인지 알기 어렵다.
- Sampling을 조심해야 하는 이유는 무엇인가?
- 비용을 줄이기 위해 샘플을 줄이면 정작 장애 요청 trace가 남지 않아 원인 분석이 어려워질 수 있기 때문이다.