The Brief FactStack이 되었습니다

FactStack

Datadog tail-based sampling으로 트레이스 볼륨 98% 줄이는 방법

데이터 신뢰성

한마디로

에러나 느린 요청만 남기고 나머지는 걸러내서 관측 비용을 크게 줄이는 Datadog 아키텍처 패턴이에요

한눈에

분산 시스템에서는 요청 하나가 여러 서비스로 퍼지면서 스팬이 기하급수로 늘어나요. Datadog이 소개한 이 가이드는 OpenTelemetry Collector의 tail-based sampling으로 트레이스가 끝난 뒤 정책에 따라 보관 여부를 판단해서, 실제 조사 가치가 있는 트레이스만 남기고 나머지는 버리는 방법을 다룹니다. 가상의 rideshare 애플리케이션 예시에서 187만 개 트레이스 중 약 2만 7천 개만 남기면서도 서비스 상태 지표는 전체 트래픽 기준으로 그대로 유지했어요.

AS-IS 트레이스 볼륨 문제

분산 시스템은 요청 하나가 여러 서비스로 퍼지면서 각 서비스가 스팬을 뿜어냅니다. 일부 애플리케이션은 시간당 수백만 트레이스를 만들고, 대형 클러스터는 하루 100억 개 넘는 스팬을 생성해요. 이 볼륨의 대부분은 정상 요청에서 나오는데, 팀이 굳이 조사하지 않을 트래픽까지 관측 백엔드로 전부 보내면 수집 비용이 늘고 쿼리가 느려지고 보존 기간이 짧아집니다.

head-based 대신 tail-based를 쓰는 이유

head-based sampling은 트레이스 시작 시점, 즉 루트 스팬에서 SDK가 보관 여부를 결정하고 이 결정을 W3C Trace Context로 하위 서비스에 전파해요. 트레이스가 끝나기 전에 결정하니까 호출 스택 깊은 곳의 에러를 놓칠 수 있고, 레이턴시 급증이 조용히 사라질 수 있습니다. tail-based sampling은 컬렉터가 트레이스의 스팬을 메모리에 버퍼링하고 완료된 뒤에 정책과 대조해서 결정해요. 메모리를 더 쓰지만 실제로 무슨 일이 일어났는지 보고 나서 판단하니까 에러와 느린 요청을 더 확실하게 남길 수 있습니다.

gateway 아키텍처와 tail_sampling 처리기

tail sampling에는 하나의 필수 조건이 있어요. 한 트레이스의 모든 스팬이 반드시 같은 컬렉터 인스턴스에 도달해야 트레이스 ID로 묶어서 정책을 적용할 수 있습니다. 이를 위해 두 계층 컬렉터로 구성하는 gateway 배포 패턴을 씁니다. 상류 컬렉터는 애플리케이션 근처에서 OTLP로 트레이스를 받아 Load Balancing exporter로 같은 트레이스 ID의 스팬을 같은 gateway 인스턴스로 보내고, gateway 컬렉터가 Span Metrics를 계산하고 tail-sampling 정책을 적용한 뒤 샘플링된 텔레메트리를 Datadog으로 내보내요. tail_sampling 처리기는 상태를 유지하는(stateful) 방식으로, decision_wait(기본 30초) 동안 스팬을 버퍼링하다가 상태 코드, 레이턴시, 서비스명, 커스텀 스팬 속성 등을 기준으로 정책과 대조해 보관 또는 폐기를 결정합니다.

Span Metrics로 전체 트래픽 상태 유지하기

Span Metrics(RED metrics, 즉 요청, 에러, 레이턴시)는 샘플링이 적용되기 전 전체 스팬 볼륨을 기준으로 계산돼요. 그래서 샘플링을 켜도 이 지표는 항상 전체 트래픽을 반영합니다. gateway는 traces/upstream 파이프라인에서 모든 스팬을 받아 Datadog Connector로 Span Metrics를 계산하고, traces/sampling 파이프라인에서 메트릭 계산이 끝난 스팬에 tail-sampling 정책을 적용해 샘플링된 스팬만 내보내는 두 개의 트레이스 파이프라인을 씁니다. 즉 Software Catalog와 Service Page는 100% 트래픽 기준 서비스 상태의 근거로 쓰고, APM Traces Explorer는 조사할 가치가 있는 개별 트레이스를 들여다보는 용도로 씁니다.

정책 설계와 실제 결과

단순한 5% 확률적 정책부터 시작하면 심각한 에러 트레이스도 정상 요청과 똑같이 취급돼서 정작 조사해야 할 트레이스를 버릴 수 있어요. 그래서 에러가 있는 트레이스, 레이턴시 임계값을 초과한 트레이스, 예상 요청률을 초과한 트레이스, 디버깅에 유용한 조건에 맞는 트레이스를 우선 보관하는 정책을 앞에 두고, 헬스체크처럼 진단 가치가 낮은 트레이스는 drop 정책으로 명시적으로 제외합니다. orchestrator와 tripsvc처럼 트래픽이 많은 서비스는 1% 낮은 비율로 샘플링하고 invert_match로 5% 폴백에 또 걸리지 않게 막아요. 이렇게 정책을 조합한 결과 187만 개 트레이스 중 약 2만 7천 개를 보관하고 184만 개는 샘플링하지 않았으며 헬스체크 3,550개는 완전히 드롭했습니다. 남은 트레이스는 느린 응답 48.5%, 에러 17.9%, 헤비 히터 9.1%, 확률적 샘플링 24.5%로 구성돼 전체 98% 감소를 달성했고, 서비스 상태 지표는 온전히 유지됐어요.

자주 묻는 질문

tail-based sampling과 head-based sampling의 차이는 무엇인가요

head-based는 트레이스 시작 시점에 루트 스팬에서 보관 여부를 결정하고 이 결정을 하위 서비스로 전파하는 방식이라 완료 전에 판단해요. tail-based는 컬렉터가 트레이스의 모든 스팬을 버퍼링해 완료된 뒤 실제 상태 코드, 레이턴시 등을 기준으로 정책과 대조해 결정합니다. 그래서 tail-based가 호출 스택 깊은 곳의 에러를 더 확실하게 잡을 수 있어요.

tail sampling을 쓰면 왜 모든 스팬이 같은 컬렉터에 도달해야 하나요

tail_sampling 처리기가 트레이스 ID로 스팬을 묶어서 정책을 평가하기 때문에, 한 트레이스의 스팬이 여러 컬렉터 인스턴스로 나뉘면 어느 컬렉터도 완전한 트레이스를 보지 못해 신뢰할 수 있는 샘플링 결정을 내릴 수 없어요. 이를 해결하려고 두 계층 gateway 배포 패턴에서 Load Balancing exporter가 같은 트레이스 ID를 항상 같은 gateway 인스턴스로 보냅니다.

샘플링을 켜도 서비스 전체 상태를 어떻게 확인하나요

Span Metrics(RED metrics)는 샘플링 적용 전 전체 스팬 볼륨으로 계산돼서 Software Catalog와 Service Page에 그대로 반영됩니다. APM Traces Explorer는 샘플링된 일부 트레이스만 보여주니까, 전체 서비스 상태는 Software Catalog를 기준으로 보고 개별 트레이스 조사는 Traces Explorer를 쓰는 식으로 역할을 나눠야 해요.

확률적 샘플링만 쓰면 어떤 문제가 생기나요

단일 확률(예 5%) 정책은 에러 트레이스도 정상 트레이스와 동일한 확률로 취급해서 조사해야 할 에러가 버려질 수 있어요. 또 트래픽이 많은 헤비 히터 서비스가 샘플링된 결과 대부분을 차지해 작은 서비스의 신호가 묻히는 문제도 생깁니다. 이 가이드에서는 헤비 히터 서비스를 더 낮은 비율로 별도 샘플링하고 invert_match로 중복 폴백을 막아 해결했어요.

에디터 노트

관측 가능성 비용을 줄이면서 에러 탐지력을 유지하는 실전 패턴이라 데이터 엔지니어링팀이 바로 참고할 만합니다. 다만 tail-based sampling은 트레이스 완료까지 스팬을 버퍼링해야 해서 메모리 요구량이 늘고, 정책 순서와 gateway 아키텍처 설계에 신경 써야 하는 만큼 도입 난이도는 head-based보다 높은 편이에요.

참고 출처 | 원문 보기

태그

용어 풀이
Datadog
데이터독
OpenTelemetry
오픈텔레메트리
tail-based sampling
테일 기반 샘플링
observability
관측 가능성

이 노트는 자동 검증을 거쳐 발행되었습니다. 오류 제보는 편집팀이 즉시 확인합니다.

공유

관련 마테크