Membahas strategi sampling OpenTelemetry: head sampling di SDK dengan parent-based dan ratio, serta tail sampling di collector dengan policy berbasis latency, error, dan trace_id, termasuk menyusun strategi hemat-biaya 100% head dengan tail cerdas untuk error dan request lambat

Semakin besar traffic, semakin terasa pertanyaan besar observability: "apakah setiap request perlu disimpan?" Mengirim 100% telemetry dari 50.000 rps ke backend bukan sekadar mahal — itu sering kali mustahil dan tidak berguna, karena sebagian besar request adalah duplikasi pola yang sama. Jawabannya adalah sampling: memilih sebagian trace untuk disimpan.
Episode 13 membedah dua pendekatan sampling yang saling melengkapi: head sampling di SDK (keputusan cepat di awal) dan tail sampling di collector (keputusan bijak setelah trace lengkap). Memahami kapan memakai yang mana adalah keterampilan SRE yang membedakan observability hemat dari observability mahal.
Head sampling menentukan sampel saat trace dimulai — di dalam SDK aplikasi, sebelum data dikirim. Karena keputusannya dibuat di root span, seluruh child span mewarisi keputusan yang sama melalui flag sampled di traceparent (bit flags episode 4).
Sampel acak dengan persentase tetap — contoh paling sederhana:
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased
from opentelemetry.sdk.trace import TracerProvider
provider = TracerProvider(sampler=TraceIdRatioBased(0.1))Sampler yang menghormati keputusan parent: jika trace datang dari service lain dengan flag sampled, ikuti; jika mulai baru, gunakan aturan lokal:
from opentelemetry.sdk.trace.sampling import ParentBased, TraceIdRatioBased
provider = TracerProvider(
sampler=ParentBased(root=TraceIdRatioBased(0.25))
)Ini wajib untuk konsistensi: tanpa parent-based, dua service bisa mengambil keputusan berbeda untuk satu trace — separuh tersimpan, separuh hilang.
Note
Cara tercepat memeriksa sampling berjalan: lihat flag sampled di header traceparent. Nilai bit terakhir 01 berarti di-sampling; 00 berarti di-drop. Ini juga cara mendeteksi sampling tidak konsisten antar service.
Tail sampling menahan trace di collector sampai seluruh span-nya lengkap, lalu memutuskan secara utuh berdasarkan kebijakan. Karena melihat trace penuh, ia bisa menyimpan justru yang penting: error, trace lambat, trace dari pelanggan tertentu.
processors:
tail_sampling:
decision_wait: 10s # tunggu trace hingga 10 detik
num_traces: 10000 # buffer maksimum
expected_new_traces_per_sec: 500
policies:
- name: keep-errors
type: status_code
status_code: {status_codes: [ERROR]}
- name: keep-slow
type: latency
latency: {threshold_ms: 1000}
- name: keep-random
type: probabilistic
probabilistic: {sampling_percentage: 10}decision_wait — berapa lama collector menahan trace sebelum memutuskan (mengorbankan sedikit latensi ekspor).status_code — simpan semua trace yang berisi span berstatus ERROR.latency — simpan trace lebih lambat dari 1 detik.probabilistic — sampel acak sisanya.Hasilnya: 100% error dan request lambat tersimpan, request normal hanya 10% — biaya turun drastis tanpa kehilangan informasi penting.
| Aspek | Head (SDK) | Tail (Collector) |
|---|---|---|
| Waktu keputusan | Awal trace | Setelah trace lengkap |
| Lokasi | SDK aplikasi | Collector |
| Informasi | Sebagian (per span awal) | Lengkap (seluruh trace) |
| Menyimpan error | Hampir tidak pernah | Sangat andal |
| Biaya operasional | Nol | CPU/memory collector |
| Latensi ekspor | Tidak ada | Sedikit (decision_wait) |
Pola produksi yang direkomendasikan menggabungkan keduanya:
Kelebihan pola ini: tidak pernah kehilangan error, biaya backend terkendali, dan aplikasi tidak perlu tahu strategi sampling — semua kebijakan hidup di collector.
Warning
Tail sampling punya biaya: collector harus menampung seluruh trace di memory selama decision_wait. Jangan menempatkan tail sampling di collector agent per-node yang memorynya kecil — tempatkan di gateway yang resource-nya dirancang untuk itu. Pahami juga bahwa tail sampling membuat pipeline per-traces hanya; metrics dan logs tidak di-tail-sample.
Ada pertimbangan yang sering terlewat: apakah backend kalian bisa menampung 100% traces? Untuk traffic rendah (beberapa ratus rps) dan backend internal, sampling mungkin tidak perlu sama sekali — simpan semuanya. Sampling baru wajib saat volume mulai menggerus biaya atau menurunkan query performance. Jangan menambahkan kompleksitas sampling sebelum dibutuhkan data nyata.
decision_wait terlalu kecil — trace lambat belum lengkap saat diputuskan, error tersembunyi.Pada episode 13 ini, kalian telah menguasai dua paradigma sampling OTel.
Inti yang harus dibawa pulang:
Di episode 14 selanjutnya, kita akan membahas buffering, backpressure & retry — queue exporter dan sending_queue di collector, sinyal backpressure (429/ResourceExhausted), konfigurasi retry/backoff, dan cara mencegah data loss saat backend down. Sampai jumpa di episode 14!