분산 추적: 요청 흐름 이해
Il 분산 추적 그리고 완전한 길을 따라갈 수 있게 해주는 기술 분산 시스템을 통한 요청의 시작점부터 최종 응답까지. 단일 사용자 요청이 10, 20개 이상을 통과할 수 있는 마이크로서비스 아키텍처에서 서비스에서 분산 추적은 흐름을 전체적으로 볼 수 있는 유일한 방법입니다. 병목 현상, 오류 및 숨겨진 종속성을 식별합니다.
각 요청은 추적하다 (트랙), 일련의 구성 기간 트리 구조로 서로 연결되어 있습니다. 각 범위는 다음을 나타냅니다. 작업 단위: HTTP 호출, 데이터베이스 쿼리, 대기열에 게시된 메시지. 스팬은 함께 처리 중에 발생한 일에 대한 전체 스토리를 알려줍니다. 요청의.
이 기사에서 배울 내용
- OpenTelemetry의 Trace 및 Span 구조
- 전파를 위한 W3C 추적 컨텍스트 프로토콜
- 범위 간 상위-하위 관계 및 링크
- SpanKind: 클라이언트, 서버, 생산자, 소비자, 내부
- 스팬 속성, 이벤트 및 상태
- 표시 패턴: 폭포수 및 서비스 맵
추적 분석
에이 추적하다 경로를 나타내는 범위의 방향성 비순환 그래프(DAG)
요청의. 각 추적에는 고유한 식별자(trace_id) 128비트
이는 관련된 모든 서비스를 통해 전파됩니다. 초기 범위는 다음과 같습니다.
루트 범위 그리고 처음부터 끝까지 전체 작업을 나타냅니다.
Trace ID: 4bf92f3577b34da6a3ce929d0e0e4736
[Root Span] API Gateway - POST /api/orders (250ms)
|
+-- [Child Span] Order Service - validate-order (15ms)
|
+-- [Child Span] Order Service - check-inventory (45ms)
| |
| +-- [Child Span] Inventory Service - GET /stock (40ms)
| |
| +-- [Child Span] Database - SELECT stock (8ms)
|
+-- [Child Span] Order Service - process-payment (120ms)
| |
| +-- [Child Span] Payment Service - charge (115ms)
| |
| +-- [Child Span] External API - Stripe charge (100ms)
|
+-- [Child Span] Order Service - send-confirmation (30ms)
|
+-- [Child Span] Notification Service - send-email (25ms)
스팬의 구조
에이 기간 추적 내의 단일 작업을 나타냅니다. 포함 무슨 일이 일어났는지, 얼마나 오래 걸렸는지 이해하는 데 필요한 모든 정보 그리고 오류가 발생한 경우. 각 범위에는 잘 정의된 구조가 있습니다.
from opentelemetry import trace
from opentelemetry.trace import StatusCode, SpanKind
tracer = trace.get_tracer("order-service", "1.0.0")
def process_payment(order_id, amount, currency):
# Creare uno span con tutti i componenti
with tracer.start_as_current_span(
name="process-payment",
kind=SpanKind.CLIENT, # Tipo di span
attributes={ # Attributi iniziali
"order.id": order_id,
"payment.amount": amount,
"payment.currency": currency,
"payment.provider": "stripe"
}
) as span:
try:
# Aggiungere un evento (timestamp automatico)
span.add_event("payment.validation.started", {
"validation.rules": "amount,currency,card"
})
validate_payment(amount, currency)
span.add_event("payment.validation.completed")
# Chiamata al provider di pagamento
result = stripe_client.charge(amount, currency)
# Aggiungere attributi dopo l'esecuzione
span.set_attribute("payment.transaction_id", result.tx_id)
span.set_attribute("payment.status", "success")
# Impostare lo status
span.set_status(StatusCode.OK)
return result
except PaymentDeclinedException as e:
# Registrare l'eccezione come evento
span.record_exception(e)
span.set_status(StatusCode.ERROR, "Payment declined")
span.set_attribute("payment.decline_reason", str(e))
raise
except TimeoutError as e:
span.record_exception(e)
span.set_status(StatusCode.ERROR, "Payment gateway timeout")
span.add_event("payment.retry.scheduled", {
"retry.attempt": 1,
"retry.delay_ms": 1000
})
raise
범위의 구성 요소
| 요소 | 설명 | Esempio |
|---|---|---|
| 추적_ID | 고유 추적 ID(128비트) | 4bf92f3577b34da6a3ce929d0e0e4736 |
| 스팬_ID | 고유 범위 ID(64비트) | 00f067aa0ba902b7 |
| parent_span_id | 상위 스팬 ID(루트의 경우 비어 있음) | a1b2c3d4e5f6a7b8 |
| 이름 | 작업을 설명하는 이름 | process-payment |
| 친절한 | 스팬 유형(CLIENT, SERVER 등) | SpanKind.CLIENT |
| 시작_시간 | 타임스탬프 시작 | 2026-02-17T10:30:00.000Z |
| 종료_시간 | 타임스탬프 종료 | 2026-02-17T10:30:00.120Z |
| 속성 | 설명적인 키-값 쌍 | payment.amount=99.99 |
| 이벤트 | 타임스탬프가 포함된 정확한 로그 | payment.validation.completed |
| 상태 | 확인, 오류 또는 설정되지 않음 | StatusCode.OK |
W3C 추적 컨텍스트: 전파 표준
Il W3C 추적 컨텍스트 추적의 컨텍스트를 정의하는 표준 서비스 경계를 넘어 전파됩니다. 두 개의 HTTP 헤더를 지정합니다. 서비스 간 모든 요청에 포함됩니다.
# Header W3C Trace Context
# traceparent: contiene trace_id, parent_span_id, trace_flags
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
| | | |
v v v v
version trace_id (32 hex) parent_span_id (16 hex) flags (sampled=01)
# tracestate: stato specifico del vendor (opzionale)
tracestate: congo=t61rcWkgMzE,rojo=00f067aa0ba902b7
서비스가 헤더가 포함된 요청을 수신하는 경우 traceparent, 추출
trace_id 그리고 parent_span_id, 동일한 하위 범위를 사용하여 새 하위 범위를 생성합니다.
trace_id 업데이트된 컨텍스트를 후속 호출에 전파합니다. 이 메커니즘
요청의 모든 범위가 동일하게 공유되도록 보장 trace_id.
SpanKind: 작업 분류
Il 스팬카인드 요청 흐름에서 범위의 역할을 분류합니다. 이 시스템 토폴로지를 재구성해야 하는 백엔드에 대한 정보 및 기본 서비스 간의 대기 시간을 계산합니다.
from opentelemetry.trace import SpanKind
# SERVER: il servizio riceve una richiesta da un client remoto
with tracer.start_as_current_span("handle-request", kind=SpanKind.SERVER):
# Gestire la richiesta HTTP in arrivo
pass
# CLIENT: il servizio invia una richiesta a un servizio remoto
with tracer.start_as_current_span("call-payment-api", kind=SpanKind.CLIENT):
# Chiamata HTTP verso payment-service
pass
# PRODUCER: il servizio invia un messaggio a un broker
with tracer.start_as_current_span("publish-order-event", kind=SpanKind.PRODUCER):
# Pubblicazione su Kafka topic
pass
# CONSUMER: il servizio riceve un messaggio da un broker
with tracer.start_as_current_span("process-order-event", kind=SpanKind.CONSUMER):
# Consumo da Kafka topic
pass
# INTERNAL: operazione interna al servizio (default)
with tracer.start_as_current_span("validate-order", kind=SpanKind.INTERNAL):
# Logica interna di validazione
pass
SpanKind 선택 규칙
- 섬기는 사람: 서비스가 동기 요청(HTTP, gRPC)의 수신자일 때 사용합니다.
- 고객: 서비스가 다른 서비스에 동기 요청을 보낼 때 사용합니다.
- 생산자: 서비스가 비동기 메시지(Kafka, RabbitMQ, SQS)를 생성할 때 사용합니다.
- 소비자: 서비스가 비동기 메시지를 소비할 때 사용
- 내부: 네트워크 경계를 넘지 않는 내부 작업에 사용
스팬 링크: 다양한 트랙 연결
부모-자식 관계 외에도 OTel은 다음을 지원합니다. 스팬 링크 연결하다 다른 트랙에 속하는 범위. 링크는 작업이 수행되는 비동기 시나리오에 유용합니다. 그것은 다른 사람에 의해 발생하지만 직계 딸은 아닙니다. 예를 들어 대기열의 메시지 소비자 추적이 다르더라도 이를 생성한 범위에 연결할 수 있습니다.
from opentelemetry import trace, context
# Scenario: batch processing di messaggi da una coda
# Ogni messaggio ha il suo trace context originale
def process_batch(messages):
# Creare link a tutti i messaggi del batch
links = []
for msg in messages:
# Estrarre il trace context dal messaggio
msg_context = extract_context(msg.headers)
span_context = trace.get_current_span(msg_context).get_span_context()
links.append(trace.Link(
context=span_context,
attributes={"messaging.message.id": msg.id}
))
# Creare uno span con link a tutti i messaggi originali
with tracer.start_as_current_span(
name="process-message-batch",
kind=SpanKind.CONSUMER,
links=links,
attributes={
"messaging.batch.message_count": len(messages)
}
) as span:
for msg in messages:
process_single_message(msg)
트랙 보기
배포된 추적은 일반적으로 두 가지 상호 보완적인 방식으로 표시됩니다.
폭포형 뷰(간트 차트)
폭포 보기에는 관계에 대한 들여쓰기와 함께 시간 순서대로 범위가 표시됩니다. 부모-자식. 이를 통해 어디서 시간이 소비되었는지, 어떤 시간이 소요되었는지 즉시 확인할 수 있습니다. 작업은 순차적 대 병렬입니다. 싱글 디버깅에 가장 많이 사용되는 보기입니다. 느린 요청.
서비스 맵(토폴로지)
서비스 맵은 서비스 간의 종속성을 방향성 그래프로 표시합니다. 각 노드는 서비스, 각각의 아치는 커뮤니케이션입니다. 집계 측정항목(지연 시간, 오류율, 처리량) 아치 위에 겹쳐져 있습니다. 그리고 전반적인 아키텍처를 이해하기 위한 이상적인 관점 중요한 서비스나 장애 지점을 식별합니다.
분산 추적 모범 사례
URL이 아닌 작업이 포함된 이름 범위: 미국 create-order, 아니다
POST /api/v1/orders. 높은 카디널리티 URL(ID 포함)은 집계 문제를 야기합니다.
비즈니스 관련 속성 추가: order.id, user.tier,
payment.method 기술 도구에서 비즈니스 분석 도구로 추적을 변환합니다.
Record_Exception을 사용하여 예외 기록: 유형, 메시지 자동 캡처
오류를 범위 이벤트로 스택 추적합니다.
SpanKind를 올바르게 사용하세요: 백엔드에서 네트워크 지연 시간을 계산할 수 있습니다.
(CLIENT 범위와 해당 SERVER 범위의 차이)
결론 및 다음 단계
분산 추적은 시스템 동작을 이해하기 위한 기본 도구입니다. 배포. 추적 컨텍스트 전파(W3C), 구조화된 범위와 속성의 조합 의미론 및 시각화 폭포/서비스 맵은 다음에 필요한 가시성을 제공합니다. 서비스 경계를 넘나드는 복잡한 문제를 진단합니다.
SpanKind의 올바른 선택, 의미 있는 속성 사용 및 이벤트 로깅 및 예외는 트랙을 단순한 타임라인에서 강력한 분석 도구로 변환합니다. 각 요청의 전체 내용을 알려줍니다.
다음 기사에서는자기 계측, 이를 가능하게 하는 기술 에이전트 및 라이브러리를 사용하여 애플리케이션 코드를 수정하지 않고 분산 추적을 얻으려면 Java, Python 및 Node.js에 대한 자동 계측.







