포스트

트레이스 샘플링 - 헤드와 테일 샘플링의 선택 기준

분산 추적을 켜면 곧 비용 문제를 만난다. 요청 하나가 서비스 다섯 개를 지나면 스팬이 수십 개 생기고, 초당 수천 요청이면 저장해야 할 양이 로그를 넘어선다. 그래서 샘플링을 켜는데, 무엇을 버릴지 정하는 방식에 따라 정작 필요한 트레이스가 남기도 하고 사라지기도 한다.

샘플링이 필요한 이유

트레이스의 비용은 세 곳에 있다.

  • 애플리케이션: 스팬 생성과 컨텍스트 전파. 크지 않지만 0은 아니다.
  • 네트워크: 수집기로 보내는 양.
  • 저장소: 보존 기간 × 양. 대개 여기가 가장 크다.

전부 저장하는 선택지가 있고, 규모가 작으면 그것이 가장 단순하다. 샘플링은 규모가 커진 뒤의 문제다.

헤드 샘플링: 시작할 때 정한다

요청이 시작되는 지점에서 “이 트레이스를 남길지”를 정하고, 그 결정을 전파한다(W3C traceparent의 sampled 플래그). 하위 서비스는 그 결정을 따른다.

  • 장점: 결정이 즉시 내려지므로 버릴 스팬은 아예 만들지 않는다. 비용이 가장 적고 구현이 단순하다.
  • 단점: 무엇이 흥미로운지 모르는 시점에 정한다. 1%를 남긴다면 드물게 나는 오류 트레이스가 남을 확률도 1%다.

확률 기반이 기본이고(TraceIdRatioBased), 그 위에 규칙을 얹는 변형이 흔하다. 예를 들어 /health는 0%, 결제 경로는 100%, 나머지는 1%처럼 경로별로 다르게 둔다. 엔드포인트별 차등이 헤드 샘플링을 실용적으로 만드는 핵심이다.

테일 샘플링: 끝나고 나서 정한다

수집기가 트레이스의 모든 스팬을 일단 받아 버퍼에 모으고, 완료된 뒤 조건을 보고 남길지 정한다.

  • 오류가 있으면 남긴다.
  • 지연이 임계값을 넘으면 남긴다.
  • 특정 속성(중요 고객, 결제 경로)이면 남긴다.
  • 나머지는 확률적으로.

필요한 것을 정확히 남길 수 있다는 것이 유일하고 결정적인 장점이다. 드문 오류를 조사할 때 “그 트레이스가 샘플링에서 빠졌다”가 사라진다.

대가가 크다.

  • 모든 스팬을 일단 전송하고 버퍼링해야 한다. 애플리케이션과 수집기 사이의 네트워크 비용은 줄지 않는다.
  • 수집기가 상태를 갖는다. 트레이스 단위로 모아야 하므로, 같은 트레이스의 스팬이 같은 수집기 인스턴스로 가야 한다. 로드 밸런싱을 트레이스 ID 기준으로 해야 하고, 수집기가 확장의 병목이 된다.
  • 완료 판정이 어렵다. 트레이스가 끝났는지 알 방법이 없으므로 타임아웃으로 결정한다. 그 시간만큼 메모리를 쓰고, 늦게 오는 스팬은 놓친다.

고르는 기준

상황선택
규모가 작다샘플링 없음. 가장 단순하다
비용만 줄이면 된다헤드 샘플링 + 경로별 차등
드문 오류 조사가 목적이다테일 샘플링
둘 다헤드에서 1차로 줄이고 테일에서 선별

실무에서 가장 흔한 것은 마지막이다. 헤드에서 명백히 불필요한 것(헬스 체크, 정적 리소스)을 걷어내고, 나머지를 테일에서 선별한다.

샘플링과 무관하게 메트릭은 전부 집계해야 한다. 트레이스를 1% 남기더라도 오류율과 지연 분포는 100% 기준으로 계산해야 한다. OpenTelemetry의 span metrics처럼 샘플링 전에 메트릭을 뽑는 구성이 이 때문에 쓰인다. 샘플링된 트레이스로 비율을 계산하면 틀린다.

이 설명이 깨지는 곳

  • 샘플링 결정은 전파되어야 한다. 중간 서비스가 컨텍스트를 잃으면 트레이스가 쪼개진다. 비동기 경계(스레드 풀, 메시지 큐)에서 자주 끊긴다.
  • 트레이스가 없어도 로그는 있다. trace_id를 로그에 남겨 두면 샘플링에서 빠진 요청도 로그로 추적할 수 있다. 둘을 함께 설계해야 하는 이유다(메트릭·로그·트레이스).
  • 1%가 얼마인지는 트래픽에 달렸다. 초당 10건이면 1%는 6분에 4건이고, 그것으로는 아무것도 조사할 수 없다. 낮은 트래픽 서비스는 샘플링하지 않는 편이 낫다.
  • 속성에 개인정보를 넣지 않는다. 트레이스는 보존 기간이 길고 여러 시스템을 지난다.

무엇을 재면 확인되는가

  1. 샘플링 비율을 바꿔 가며 “특정 오류의 트레이스를 찾을 확률”을 센다. 조사 가능성이 숫자로 나온다.
  2. 테일 샘플링 수집기의 메모리 사용량을 트레이스 수와 버퍼 타임아웃의 함수로 본다.
  3. 샘플링된 트레이스로 계산한 오류율과 전량 메트릭의 오류율을 비교한다. 차이가 나면 전자를 지표로 쓰고 있었다는 뜻이다.

실무와의 접점

monticker의 OpenTelemetry 도입에서 sampling.probability: 1.0을 개발 환경 값으로 두고 “운영에서는 0.1 이하로 줄여야 한다”고 적었다. 지금 보면 그 문장에 빠진 것이 “무엇을 남길 것인가” 다. 비율만 줄이면 조사에 필요한 것도 같은 비율로 사라진다. 운영으로 가져간다면 헤드에서 헬스 체크를 걷어내고, 오류와 느린 요청은 테일에서 남기는 구성이 필요하다.

정리

  • 트레이스 비용은 대부분 저장소에 있고, 샘플링은 규모가 커진 뒤의 문제다.
  • 헤드 샘플링은 시작 시점에 정해 전파한다. 싸지만 무엇이 흥미로운지 모른 채 정한다.
  • 테일 샘플링은 완료 후 조건으로 정한다. 필요한 것을 남기지만 수집기가 상태를 갖고 병목이 된다.
  • 경로별 차등이 헤드 샘플링을 실용적으로 만든다.
  • 메트릭은 샘플링과 무관하게 전량 집계해야 한다. 샘플된 트레이스로 비율을 계산하면 틀린다.
  • 트래픽이 낮으면 샘플링하지 않는 편이 낫다.

참고

장애 대응과 관측 아키텍처와 마이그레이션
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

댓글

아직 댓글이 없습니다