개요
분산 추적 컨텍스트를 어디에 어떻게 실어 나를지에 대한 표준 패턴 정리. 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>-01Kafka 메시지에 헤더로 전파
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를 기본으로 삼고, 각 통신 채널의 제약에 맞춰 일관된 전파 전략 수립이 핵심임