개요

분산 추적 컨텍스트를 어디에 어떻게 실어 나를지에 대한 표준 패턴 정리. HTTP 같은 동기식 통신과 메시지 큐 같은 비동기식 통신은 전달 수단이 다름. 업계 표준은 W3C Trace Context와 이를 구현한 OpenTelemetry를 따르는 흐름임

핵심 개념

  • trace-id, span-id, sampling 플래그 등 추적 컨텍스트 전달 필요
  • 동기식 요청/응답 채널은 헤더 기반 메타데이터 전달이 자연스러움
  • 비동기 메시징은 메시지 자체가 전달 단위이므로 페이로드 또는 메시지 속성 이용
  • 채널이 헤더 개념을 지원하면 헤더 우선, 없으면 페이로드에 포함

통신별 패턴

  • HTTP/REST 통신: 요청/응답 헤더에 trace 컨텍스트 실어 전달
  • gRPC: 메타데이터(헤더 개념)로 전달
  • Kafka: 메시지 헤더 지원. 가능하면 헤더 사용 권장
  • RabbitMQ: 메시지 프로퍼티의 headers 사용 가능
  • AWS SQS: Message Attributes 사용 가능. 미지원 시 Body에 포함
  • BullMQ/Redis 기반 잡 큐: 헤더 개념 없음. Job data에 포함
  • WebSocket: 초기 핸드셰이크 단계에서 허용된 메타데이터 채널 또는 쿼리로 전달, 이후 각 메시지 페이로드에 포함. 환경 제약으로 커스텀 헤더 불가한 경우 존재

산업 표준

  • OpenTelemetry는 W3C Trace Context를 구현하는 업계 표준 스택
  • HTTP는 W3C traceparent, tracestate 헤더 사용
  • 비동기 메시징은 채널이 헤더를 지원하면 헤더 사용, 아니면 데이터에 포함하는 전략 일반화

예시

traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
            └─ trace-id ────────────┘  └─ span-id ──┘

비동기 메시지에 컨텍스트 포함 예시

{
  "traceId": "0af7651916cd43dd8448eb211c80319c",
  "spanId": "b7ad6b7169203331",
  "data": { "...": true }
}

왜 채널별로 다르게 전파하나

  • HTTP는 요청-응답 모델. 헤더가 양방향 메타데이터 전달의 표준 수단이라 헤더 사용이 자연스러움
  • 메시지 큐는 fire-and-forget 모델. 메시지가 독립적 단위라 메시지 헤더 또는 페이로드에 컨텍스트를 포함하는 편이 합리적임

채널별 구현 힌트

  • HTTP/REST: W3C traceparent, tracestate 사용. 레거시 시스템은 x-trace-id, x-request-id 같이 커스텀 헤더를 병행하기도 함
  • gRPC: 메타데이터에 traceparent 전파
  • Kafka: headers에 trace-id 등 삽입. 헤더 미사용 시 value에 포함
  • RabbitMQ: properties.headers.trace-id 형태 권장
  • AWS SQS: MessageAttributes에 trace 관련 키 삽입. 컨수머에서 Attributes 추출 실패 시 Body fallback 고려
  • BullMQ: job.data에 tid 포함 외 대안 없음
  • WebSocket: 초기 연결 시 허용된 채널(프로토콜 네고, 쿼리, 쿠키 등)로 컨텍스트 전달. 이후 애플리케이션 메시지에 tid 필드 포함

베스트 프랙티스

  • 가능한 표준 헤더 사용 우선. 지원하지 않는 채널에서만 페이로드 포함 전략 채택
  • traceparent의 sampling 플래그와 tracestate를 보존. 재발급이 아닌 전파를 기본으로 함
  • 컨텍스트 키는 케이스와 하이픈 규칙 일관성 유지. 채널 제약에 맞춰 스네이크/카멜케이스 변환 필요 시 매핑 테이블 유지
  • 메시지 크기와 헤더 용량 제한 고려. 대형 오브젝트를 컨텍스트에 넣지 않음
  • 보안 민감 정보는 컨텍스트에 포함 금지. 추적용 상관관계 식별자만 전파
  • 수신 측에서 유효성 검증. 잘못된 형식이면 새 트레이스 시작 또는 드롭 정책 정의

최소 예시 스니펫

HTTP 요청에 traceparent 주입과 추출

GET /api HTTP/1.1
traceparent: 00-<trace-id>-<span-id>-01

Kafka 메시지에 헤더로 전파

producer.send({ topic: 't', messages: [{ headers: { 'trace-id': tid }, value: payload }] })
// consumer 측에서 message.headers['trace-id'] 추출

BullMQ 잡 데이터에 포함

queue.add('job', { tid, payload })

마무리

원칙은 단순함. 채널이 헤더 기반 메타데이터를 지원하면 헤더 사용, 아니면 메시지 데이터에 포함. W3C Trace Context와 OpenTelemetry를 기본으로 삼고, 각 통신 채널의 제약에 맞춰 일관된 전파 전략 수립이 핵심임

참고자료