テールサンプリングのポリシーとルーティング層
한국어 원문으로 표시합니다.
목표
테일 샘플링 정책을 다섯 개 설계하고, 그 앞에 trace ID 라우팅 계층을 두고, 버퍼 메모리를 직접 계산해 그 값을 오퍼레이터 CR 에 반영합니다.
왜 중요한가
테일 샘플링은 "켜면 비용이 준다"는 기능이 아닙니다. 판정하려면 모든 스팬이 도착해야 하므로 에이전트에서 컬렉터까지의 네트워크는 전혀 줄지 않고, 줄어드는 것은 백엔드 저장과 인덱싱뿐입니다. 대신 세 가지를 새로 지불합니다. decision_wait 동안 모든 스팬을 들고 있어야 하는 메모리, 같은 트레이스를 한 인스턴스로 모으는 라우팅 계층, 그리고 그 계층을 운영하는 복잡도입니다. 그래서 도입 판단은 감이 아니라 곱셈으로 합니다. 초당 트레이스 수와 대기 시간을 곱해 num_traces 를 정하고, 거기에 스팬 수와 크기를 곱해 메모리를 정합니다. 이 계산을 건너뛰면 상한이 모자란 채로 운영되다가, 오래된 트레이스가 강제 판정되면서 데이터가 사라지는데 지표는 아무 이상도 보고하지 않는 상황을 만나게 됩니다.
단계
/root/otca-sampling/tailsampling.yaml을 만들고processors.tail_sampling에decision_wait: 30s,num_traces: 300000,expected_new_traces_per_sec: 10000을 씁니다.policies에 두 정책을 넣습니다.name: keep-errors(type: status_code,status_code.status_codes에ERROR)와name: keep-slow(type: latency,latency.threshold_ms: 800).name: drop-healthchecks정책을 추가합니다.type: string_attribute,string_attribute.key: http.route,values는/healthz와/readyz, 그리고invert_match: true.name: vip-slow정책을 추가합니다.type: and이고and.and_sub_policy에 두 하위 정책 —type: string_attribute로tenant.tier가enterprise인 것과,type: latency로threshold_ms: 300인 것. 마지막으로name: baseline(type: probabilistic,probabilistic.sampling_percentage: 2)을 추가해 정책을 총 5개로 만듭니다./root/otca-sampling/loadbalancing.yaml에 앞단 라우팅 계층을 씁니다.exporters.loadbalancing에routing_key: traceID,resolver.dns.hostname은otel-tailsampler를 포함한 서비스 주소,resolver.dns.port: 4317.service.pipelines.traces의 익스포터는[loadbalancing]하나이고, 프로세서에tail_sampling을 넣으면 안 됩니다./root/otca-sampling/buffer-memory.txt에 계산 결과를 세 줄로 씁니다.num_traces_required=(10,000 trace/s × 30s),buffer_mb=(10,000 × 30 × 12스팬 × 1.2KB 를 MB 로 환산해 반올림),buffer_mb_with_headroom=(그 2배). 각 줄은 공백 없이키=값형태입니다.- 네임스페이스
otca-sampling을 만들고/root/otca-sampling/collector-cr.yaml에 CR 을 씁니다.apiVersion: opentelemetry.io/v1beta1,kind: OpenTelemetryCollector,metadata.name: otel-tailsampler,metadata.namespace: otca-sampling,spec.mode: deployment,spec.replicas: 3.spec.config안에는 1~4단계의tail_sampling(정책 5개 그대로)을 담고,spec.config.service.pipelines.traces.processors는tail_sampling이batch보다 앞에 오고batch가 마지막이 되도록 씁니다.
참고
- 6단계 계산: 10000 × 30 × 12 × 1.2 = 4,320,000 KB 입니다. 이것을 1024 로 나누고 반올림하세요.
- 7단계의
spec.config구조는 일반 컬렉터 설정 파일과 동일합니다.receivers,processors,exporters,service를 그 안에 그대로 넣습니다. - 흔한 실수 1:
invert_match를 빼먹는 것. 그러면 헬스체크만 남기게 됩니다. - 흔한 실수 2: 앞단 라우팅 계층에
tail_sampling을 함께 넣는 것. 스팬이 모이기 전에 판정하게 됩니다. - 흔한 실수 3: CR 의
spec.mode를daemonset으로 두는 것. 노드마다 스팬이 흩어져 판정이 불가능합니다.
tail_sampling 기본값
/root/otca-sampling/tailsampling.yaml 을 만들고 processors.tail_sampling 에 decision_wait: 30s, num_traces: 300000, expected_new_traces_per_sec: 10000 을 씁니다.
decision_wait 은 트레이스의 모든 스팬이 도착할 시간적 여유입니다. 너무 짧으면 불완전한 트레이스로 판정하고, 너무 길면 메모리가 급증합니다. num_traces 는 초당 트레이스 수와 대기 시간의 곱에서 나옵니다.
결과 기반 정책 두 개
policies 에 두 정책을 넣습니다. name: keep-errors(type: status_code, status_code.status_codes 에 ERROR)와 name: keep-slow(type: latency, latency.threshold_ms: 800).
테일 샘플링의 존재 이유가 이 두 정책입니다. 헤드 샘플링으로는 확률적으로만 얻을 수 있는 것을 규칙으로 100% 보존합니다. 각 정책은 name 과 type, 그리고 type 과 같은 이름의 설정 블록을 갖습니다.
헬스체크 제외
name: drop-healthchecks 정책을 추가합니다. type: string_attribute, string_attribute.key: http.route, values 는 /healthz 와 /readyz, 그리고 invert_match: true.
정책은 모두 '남길 조건'입니다. 그래서 특정 라우트를 빼려면 매칭을 뒤집는 옵션이 필요합니다. 속성 값 목록으로 매칭하는 정책 타입을 쓰세요.
and 조합 정책과 기본 확률
name: vip-slow 정책을 추가합니다. type: and 이고 and.and_sub_policy 에 두 하위 정책 — type: string_attribute 로 tenant.tier 가 enterprise 인 것과, type: latency 로 threshold_ms: 300 인 것. 마지막으로 name: baseline(type: probabilistic, probabilistic.sampling_percentage: 2)을 추가해 정책을 총 5개로 만듭니다.
두 조건을 동시에 만족할 때만 남기려면 조합 정책이 필요합니다. 하위 정책들도 각각 name 과 type 을 갖는 완전한 정책입니다. 마지막에는 나머지를 위한 확률 정책을 둡니다.
앞단 라우팅 계층
/root/otca-sampling/loadbalancing.yaml 에 앞단 라우팅 계층을 씁니다. exporters.loadbalancing 에 routing_key: traceID, resolver.dns.hostname 은 otel-tailsampler 를 포함한 서비스 주소, resolver.dns.port: 4317. service.pipelines.traces 의 익스포터는 [loadbalancing] 하나이고, 프로세서에 tail_sampling 을 넣으면 안 됩니다.
판정 계층 앞에는 같은 트레이스의 스팬을 한 인스턴스로 모으는 계층이 필요합니다. 일반 로드밸런서로는 안 되고, 트레이스 ID 를 키로 쓰는 익스포터를 씁니다. 이 앞단 계층은 판정을 하지 않습니다.
버퍼 메모리 계산
/root/otca-sampling/buffer-memory.txt 에 계산 결과를 세 줄로 씁니다. num_traces_required=(10,000 trace/s × 30s), buffer_mb=(10,000 × 30 × 12스팬 × 1.2KB 를 MB 로 환산해 반올림), buffer_mb_with_headroom=(그 2배). 각 줄은 공백 없이 키=값 형태입니다.
초당 트레이스 수 곱하기 대기 시간 곱하기 트레이스당 스팬 수 곱하기 스팬 크기입니다. KB 를 MB 로 바꿀 때는 1024 로 나누고 소수점은 반올림합니다. num_traces 필요값은 앞의 두 항만 곱하면 나옵니다.
OpenTelemetryCollector CR
네임스페이스 otca-sampling 을 만들고 /root/otca-sampling/collector-cr.yaml 에 CR 을 씁니다. apiVersion: opentelemetry.io/v1beta1, kind: OpenTelemetryCollector, metadata.name: otel-tailsampler, metadata.namespace: otca-sampling, spec.mode: deployment, spec.replicas: 3. spec.config 안에는 1~4단계의 tail_sampling(정책 5개 그대로)을 담고, spec.config.service.pipelines.traces.processors 는 tail_sampling 이 batch 보다 앞에 오고 batch 가 마지막이 되도록 씁니다.
노드마다 뜨는 배포 모드에서는 한 트레이스의 스팬이 여러 노드로 흩어져 판정이 불가능합니다. CR 안의 설정은 컬렉터 설정 파일과 같은 구조이고, 프로세서 순서 규칙도 그대로 적용됩니다. CRD 가 없는 환경이므로 파일만 쓰고 네임스페이스만 실제로 만듭니다.