Belajar OpenTelemetry - Tuning & Performance Optimization
Episode 19 of 23

Belajar OpenTelemetry - Tuning & Performance Optimization

Mengoptimalkan performa pipeline telemetry: tuning memory dan CPU collector, menyetel memory_limiter, konfigurasi concurrency, mengendalikan cardinality metrics, melakukan load test pipeline, dan profiling collector memakai pprof

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Semua episode sebelumnya membangun pipeline yang benar. Episode 19 membangun pipeline yang efisien — karena di skala produksi, observability adalah beban yang harus dibayar: memory collector, CPU untuk parsing, dan biaya backend per series metrics. Pipeline yang tidak dituning akan diam-diam menggerus resource cluster.

Mengapa penting? Collector yang boros memory akan di-restart oleh K8s; metrics ber-cardinality liar akan meledakkan biaya dan memperlambat query; dan pipeline yang tidak di-load test akan mengejutkan kalian tepat saat traffic tinggi — momen ketika observability paling dibutuhkan.

Tuning Memory Collector

memory_limiter: Dasar yang Benar

Tuning memory_limiter membutuhkan angka yang diukur, bukan ditebak. Aturannya:

  • limit_mib sekitar 80% dari limit memory container (sisanya untuk runtime dan spike).
  • spike_limit_mib sekitar 20-25% dari limit — ruang untuk lonjakan sesaat.
  • Pantau otelcol_processor_..._limit_mib dan otelcol_processor_..._spike_limit_mib untuk memverifikasi.
memory_limiter untuk container 1Gi
processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 800
    spike_limit_mib: 200

Jika collector sering thrash (GC terus-menerus, refusal naik), cek dulu komponen mana yang paling boros — jangan asal menaikkan limit.

Cache & Queue

  • batch yang terlalu besar menambah memory (batch dipegang sampai terkirim) — sesuaikan send_batch_size dengan throughput.
  • sending_queue (episode 14) adalah pemakai memory utama — queue_size besar berarti memory besar; hitung 1 item kira-kira beberapa ratus byte sampai beberapa KB tergantung data.

Tuning CPU & Concurrency

Collector berbasis Go — CPU tuning sebagian besar lewat paralelisme pipeline:

Concurrency config
exporters:
  otlp/backend:
    endpoint: jaeger:4317
    tls:
      insecure: true
    sending_queue:
      enabled: true
      queue_size: 5120
      num_consumers: 4
 
processors:
  batch:
    timeout: 2s
    send_batch_size: 1024
    send_batch_max_size: 2048
  • num_consumers — berapa goroutine pengirim paralel; mulai dari 4, ukur, naikkan bila antrean menumpuk.
  • send_batch_max_size — mencegah batch membesar tak terkendali saat lonjakan.
  • Go runtime otomatis memakai semua core; batasi hanya bila ada CPU throttling di container (misal lewat GOMAXPROCS via flag --gomemlimit atau env).

Tip

Sebelum men-tune concurrency, ukur dulu. Satu collector contributor yang dikonfigurasi benar bisa meneruskan ratusan ribu span/detik. Jika collector kalian "selalu penuh", kemungkinan besar masalahnya bukan CPU — melainkan cardinality (metrik seri membengkak) atau queue tanpa batas.

Kontrol Cardinality Metrics

Cardinality adalah jumlah kombinasi unique key=value dalam satu metric. Attribute ber-kardinalitas tinggi (user_id, request_id, ip_address) membuat satu metric meledak menjadi jutaan series — biaya backend dan query melambat.

Strategi pengendalian:

  1. Di SDK (terbaik) — jangan pernah merekam attribute ber-cardinalitas tinggi; gunakan attribute low-cardinality (route, status class, region).
Hindari attribute ber-cardinality tinggi
# Buruk: satu series per user_id → meledak
latency.record(d, {"user_id": user.id})
 
# Baik: cardinality rendah, tetap berguna
latency.record(d, {"http.route": route, "http.response.status_code": status})
  1. Di collectortransform processor untuk menghapus key liar sebelum diekspor:
Buang attribute ber-cardinality tinggi
processors:
  transform/cardinality:
    error_mode: ignore
    metric_statements:
      - context: datapoint
        statements:
          - delete_key(attributes, "request_id")
          - delete_key(attributes, "user_id")
  1. View di SDK — memakai View dengan aggregation untuk mengabaikan attribute tertentu (episode 5).

Ukur cardinality dengan query backend (misal PromQL count(metric)), lalu bandingkan sebelum/sesudah perbaikan.

Load Test Pipeline

Sebelum men-tune lebih jauh, kalian butuh baseline. Jalankan load test ringan yang mengirim telemetry buatan ke collector dan ukur throughput:

Gunakan telemetrygen untuk load test
docker run --rm \
  -v "$PWD/config.yaml:/etc/config.yaml" \
  ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen \
  traces --otlp-endpoint localhost:4317 \
         --traces 100000 --workers 8 \
         --otlp-attributes service.name=load-test

Metrik yang diperhatikan selama test:

  • otelcol_receiver_accepted_spans vs otelcol_receiver_refused_spans.
  • otelcol_exporter_sent_spans vs otelcol_exporter_send_failed_spans.
  • otelcol_exporter_queue_size — naik terus = hilir tidak mampu mengimbangi.
  • process_runtime_heap_alloc_bytes / GC pause — memory sehat?

Warning

Load test yang benar menguji seluruh pipeline, bukan collector sendirian. Backend yang ikut diuji (Jaeger, Prometheus) bisa jadi bottleneck sesungguhnya. Mulailah dari volume kecil dan naikkan bertahap sambil memantau semua metrik internal — jangan langsung membanjiri dengan volume maksimal.

Profiling Collector dengan pprof

Saat CPU collector tinggi tanpa penyebab yang jelas, aktifkan pprof:

Aktifkan pprof endpoint
service:
  telemetry:
    profilers:
      block:
        enabled: true
      memory:
        enabled: true
      cpu:
        enabled: true

Lalu ambil profile dari port 1777:

Ambil CPU profile 30 detik
curl -o cpu.prof "http://localhost:1777/debug/pprof/profile?seconds=30"
go tool pprof -top cpu.prof

Hasil -top menunjukkan fungsi mana yang menyedot CPU — sering kali ini mengarah pada regex redaksi yang mahal, komponen parsing yang tak terduga, atau GC yang terlalu agresif.

Common Pitfalls

  • Memory limiter dipasang setelah processor boros — urutkan paling awal (episode 12).
  • Cardinality dibiarkan sampai backend mahal — kendalikan sejak SDK, bukan baru di backend.
  • Load test tanpa memantau metric internal — angka throughput tanpa konteks menyesatkan.
  • pprof diaktifkan tanpa akses terkontrol — jangan ekspos port profiling ke publik.

Penutup

Pada episode 19 ini, kalian telah mengoptimalkan performa pipeline telemetry.

Inti yang harus dibawa pulang:

  • Tuning memory dimulai dari memory_limiter yang benar (80% limit) dan dipantau dengan metric internal.
  • Concurrency dikendalikan lewat num_consumers dan send_batch_max_size — ukur dulu sebelum mengubah.
  • Cardinality metrics adalah biaya terbesar yang tersembunyi — kendalikan di SDK dan buang di collector.
  • Load test dengan telemetrygen, dan profiling dengan pprof saat CPU tidak jelas penyebabnya.

Di episode 20 selanjutnya, kita akan membahas multi-backend & cloud observability — routing ke beberapa backend sekaligus (fan-out) atau per-sinyal, serta distro cloud seperti AWS Distro ADOT, GCP OTel, dan Azure Monitor dengan strategi multi-vendor. Sampai jumpa di episode 20!

Belajar OpenTelemetry - Tuning & Performance Optimization | Belajar OpenTelemetry