Kodeloka
  1. Kodeloka
  2. Kelas Microservices
  3. Materi

Keandalan · Modul 18 dari 24

Distributed Tracing & Observability

Melacak satu permintaan yang melintasi banyak layanan dengan trace, span, dan context propagation memakai OpenTelemetry, serta menggabungkannya dengan log dan metrik.

1. Kenapa Log Saja Tidak Cukup

Pengguna melapor: "checkout lambat, sekitar 8 detik"

Log Layanan Pesanan     : "memproses pesanan p-1001"  ... 8,2 detik
Log Layanan Stok        : "cek stok"                  ... 0,1 detik
Log Layanan Harga       : "hitung diskon"             ... 0,2 detik
Log Layanan Pembayaran  : "tagih kartu"               ... 0,3 detik

Total yang terlihat: 0,6 detik. Lalu 7,6 detik sisanya ke mana?

Tanpa tracing, Anda hanya punya potongan-potongan terpisah tanpa tahu urutan, hubungan induk-anak, dan celah waktu di antaranya. Tracing menyusun potongan itu menjadi satu lini masa utuh.

2. Trace, Span, dan Hubungan Induk-Anak

Trace ID: 4bf92f3577b34da6a3ce929d0e0e4736

├─ POST /checkout                          8,20 dtk  [Gateway]
│  ├─ POST /pesanan                        8,15 dtk  [Layanan Pesanan]
│  │  ├─ SELECT pengguna                   0,02 dtk  [PostgreSQL]
│  │  ├─ GET /stok/cek                     0,10 dtk  [Layanan Stok]
│  │  ├─ GET /harga/hitung                 0,20 dtk  [Layanan Harga]
│  │  ├─ ⚠ SELECT riwayat_pesanan          7,50 dtk  [PostgreSQL]  <-- INI
│  │  └─ POST /pembayaran                  0,30 dtk  [Layanan Pembayaran]
│  └─ serialisasi respons                  0,05 dtk

Ketemu: sebuah kueri database tanpa indeks. Tanpa tracing, menemukan ini bisa memakan waktu berhari-hari.

IstilahArti
TraceSeluruh perjalanan satu permintaan lintas semua layanan
SpanSatu satuan pekerjaan: panggilan HTTP, kueri DB, pemrosesan pesan
Trace IDPengenal 16 byte, sama untuk seluruh perjalanan
Span IDPengenal 8 byte untuk satu span
Parent Span IDYang membentuk struktur pohon
AttributePasangan kunci-nilai: http.method, db.statement, pengguna.id
EventPenanda waktu di dalam span, misal "cache miss"

3. Context Propagation — Bagian yang Paling Sering Rusak

Agar trace tersambung, konteksnya harus ikut mengalir bersama setiap panggilan. Standarnya adalah header W3C Trace Context.

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
             │  │                                │                │
             │  │                                │                └─ flag (01 = direkam)
             │  │                                └─ parent span id
             │  └─ trace id
             └─ versi

tracestate: vendor1=nilai,vendor2=nilai   (opsional, khusus vendor)
🚫 Trace putus di batas asinkron

Propagasi otomatis biasanya berjalan mulus untuk HTTP dan gRPC. Yang sering putus adalah saat pesan masuk ke antrian. Bila Anda menerbitkan ke RabbitMQ atau Kafka tanpa menyisipkan traceparent ke header pesan, consumer akan memulai trace yang benar-benar baru — dan hubungan sebab-akibatnya hilang. Sisipkan konteks ke header pesan saat menerbitkan, dan ekstrak kembali saat mengonsumsi.

4. OpenTelemetry — Standar Netral Vendor

Aplikasi (SDK OpenTelemetry)
      │  protokol OTLP
      ▼
OpenTelemetry Collector  ← satu titik untuk memproses semuanya
      │       │       │
      ▼       ▼       ▼
   Tempo   Jaeger  Prometheus / Loki / vendor komersial
💡 Kenapa memakai Collector, bukan mengirim langsung
  • Aplikasi tidak perlu tahu tujuan akhirnya. Ganti backend cukup dengan mengubah konfigurasi Collector, tanpa deploy ulang seluruh layanan.
  • Tempat menyaring data sensitif sebelum keluar dari jaringan Anda.
  • Tempat mengatur sampling secara terpusat.
  • Buffer saat backend sedang tidak tersedia.
  • Menambahkan atribut seragam seperti nama kluster, wilayah, dan lingkungan.
otel-collector.yaml
receivers:
  otlp:
    protocols:
      grpc: { endpoint: 0.0.0.0:4317 }
      http: { endpoint: 0.0.0.0:4318 }

processors:
  batch:
    timeout: 5s
  memory_limiter:
    limit_mib: 512
  attributes:
    actions:
      - key: pengguna.email      # jangan pernah kirim PII keluar
        action: delete

exporters:
  otlp/tempo:
    endpoint: tempo:4317
  prometheus:
    endpoint: 0.0.0.0:8889

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, attributes, batch]
      exporters: [otlp/tempo]

5. Sampling — Anda Tidak Bisa Menyimpan Semuanya

StrategiCara kerjaCatatan
Head samplingDiputuskan di awal, misal simpan 10% acakMurah, tapi trace yang error bisa ikut terbuang
Tail samplingDiputuskan setelah trace selesaiBisa menyimpan semua yang error dan lambat; butuh memori di Collector
Berbasis aturanSelalu simpan endpoint kritis, sampel jarang untuk health checkPaling praktis di produksi
📌 Konfigurasi yang masuk akal untuk memulai

Simpan 100% trace yang mengandung error atau melebihi ambang latensi, dan 1–5% dari trace normal. Anda tetap punya gambaran statistik dari sampel, sekaligus memiliki bukti lengkap untuk setiap kejadian yang benar-benar penting.

6. Menghubungkan Tiga Pilar

METRIK  (Prometheus)  -> "ada apa?"    Tingkat error naik ke 5%
   │ exemplar: trace_id
   ▼
TRACE   (Tempo)       -> "di mana?"   Layanan Pembayaran, span 7,5 dtk
   │ trace_id
   ▼
LOG     (Loki)        -> "kenapa?"    "connection pool exhausted"
💡 Kunci penghubungnya: sertakan trace_id di setiap baris log
{
  "waktu": "2026-07-28T10:15:32Z",
  "level": "error",
  "layanan": "pembayaran",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "pesan": "kolam koneksi habis",
  "pesanan_id": "p-1001"
}

Dengan ini, dari satu trace yang lambat Anda bisa langsung melompat ke semua log yang dihasilkan permintaan itu — di seluruh layanan sekaligus. Inilah yang mengubah investigasi insiden dari berjam-jam menjadi beberapa menit.

7. Metrik yang Perlu Dipantau: Metode RED

R - Rate      : jumlah permintaan per detik
E - Errors    : jumlah permintaan yang gagal per detik
D - Duration  : distribusi lama pemrosesan (p50, p95, p99)

Untuk sumber daya, pakai metode USE:
U - Utilization : persentase pemakaian
S - Saturation  : panjang antrian
E - Errors      : jumlah kesalahan
⚠️ Rata-rata menyembunyikan penderitaan pengguna

Latensi rata-rata 200 ms terdengar bagus. Tetapi bila p99 adalah 8 detik, satu dari seratus permintaan sangat buruk — dan pengguna yang membuka sepuluh halaman punya peluang besar merasakannya. Selalu pantau persentil, bukan rata-rata. Untuk sistem yang serius, pantau juga p99,9.

8. Kesalahan Umum

  • Kardinalitas metrik meledak. Jangan pernah menjadikan ID pengguna, ID pesanan, atau URL lengkap sebagai label metrik — itu membuat Prometheus kehabisan memori. Informasi berkardinalitas tinggi tempatnya di trace dan log, bukan metrik.
  • Log tanpa struktur. Log berbentuk kalimat bebas tidak bisa dikueri. Gunakan JSON dengan field yang konsisten.
  • Data pribadi di dalam span. Email, nomor kartu, dan token tidak boleh masuk ke atribut span. Saring di Collector.
  • Instrumentasi hanya di batas HTTP. Span yang tidak mencakup kueri database dan panggilan cache menyembunyikan justru bagian yang paling sering menjadi biang keladi.
  • Alert pada gejala, bukan penyebab. Beri alert pada hal yang dirasakan pengguna (tingkat error, latensi), bukan pada "CPU 80%" yang belum tentu berarti apa-apa.