L
Observability & Monitoring β€’ Literally Web ID

Membangun Sistem Observability & Distributed Tracing End-to-End dengan OpenTelemetry

⏱️ 15 menit baca β€’ πŸ“… 14 Oct 2026 β€’ πŸ‘οΈ 1 views
Membangun Sistem Observability & Distributed Tracing End-to-End dengan OpenTelemetry

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap arsitektur perangkat lunak modern, pergeseran dari monolitik menuju layanan terdistribusi (microservices) telah membawa tantangan operasional yang masif. Sebuah permintaan tunggal dari klien (end-user) kini dapat melintasi puluhan lapisan infrastruktur: melewati edge CDN (Cloudflare), load balancer (Nginx), WAF, aplikasi gateway, berbagai layanan backend dengan bahasa pemrograman berbeda (Golang, Node.js, PHP-FPM), sistem antrean (Redis/RabbitMQ), hingga beberapa klaster database (MySQL/MariaDB). Ketika terjadi lonjakan latensi atau kegagalan transaksi (error 500), proses debugging menjadi mimpi buruk bagi Site Reliability Engineers (SRE) dan Backend Engineers.

Secara tradisional, tim mengandalkan centralized logging dan metrics monitoring yang terisolasi. Namun, pendekatan ini memiliki celah fatal: metrik (seperti Prometheus) hanya memberi tahu bahwa sistem sedang lambat, dan log (seperti ELK Stack) memberi tahu bahwa terjadi error, tetapi tidak ada korelasi kontekstual yang menghubungkan perjalanan sebuah request melintasi batas-batas layanan. Hal ini memicu fenomena "MTTR (Mean Time to Resolution) Fatigue", di mana insinyur menghabiskan waktu berjam-jam hanya untuk menebak layanan mana yang menjadi akar masalah (root cause).

Kondisi Sebelum vs Sesudah Penerapan OpenTelemetry

Parameter Sebelum OpenTelemetry (Terfragmentasi) Sesudah OpenTelemetry (Unified Observability)
Metode Tracing Ad-hoc, custom header (X-Request-ID) manual tanpa standar industri. Standarisasi W3C Trace Context, lintas bahasa dan protokol secara otomatis.
Korelasi Data Terputus antara Metrics, Logs, dan Traces. Analisis manual melalui grep log. Korelasi instan: klik pada spike latensi di grafik Grafana langsung merujuk ke trace dan log spesifik.
Vendor Lock-in Tinggi. Menggunakan agen proprietary (Datadog, New Relic) dengan biaya lisensi eskalatif. Rendah. OpenTelemetry adalah standar CNCF vendor-agnostic; data dapat dikirim ke backend open-source (Grafana Tempo, Prometheus, Jaeger) maupun komersial.
Overhead Performa Agen monitoring lama sering menyebabkan memory leak dan CPU overhead tinggi. OpenTelemetry SDK dirancang dengan prinsip zero-allocation di hot paths dan sampling adaptif.

2. Konsep Inti & Deep Dive Arsitektur

OpenTelemetry (OTel) bukan sekadar alat, melainkan kerangka kerja observabilitas (observability framework) komprehensif yang disediakan oleh Cloud Native Computing Foundation (CNCF), hasil penggabungan proyek OpenTracing dan OpenCensus. Tiga pilar utamanyaβ€”Metrics, Logs, dan Tracesβ€”diintegrasikan ke dalam satu aliran data terpadu.

Arsitektur Alur Data Under The Hood

[Client / Browser]
       β”‚
       β–Ό HTTP Request (W3C TraceContext headers)
[Nginx / Reverse Proxy] ──(OTel Module / Log)──┐
       β”‚                                       β”‚
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                        β”‚
       β–Ό              β–Ό                        β–Ό
[Go Backend]    [Node.js Backend]      [OpenTelemetry Collector]
(gRPC Export)   (OTLP/HTTP Export)     - Receiver (OTLP, Prometheus, Jaeger)
       β”‚              β”‚                - Processor (Batch, Memory Limiter, Attributes)
       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                - Exporter (Grafana Tempo, Prometheus)
              β–Ό
      [Redis / MySQL DB]
              β”‚ (SQL Comment Injection / Context Propagation)
              β–Ό
      [Database Instrumentation]

Komponen inti dalam ekosistem ini meliputi:

  1. API & SDK: Pustaka spesifik bahasa (Go, Node.js, PHP, Python, Java) yang diintegrasikan ke dalam kode aplikasi untuk menghasilkan telemetry data.
  2. OpenTelemetry Collector: Agen atau gateway pusat yang bertugas menerima (receive), memproses (process), dan mengekspor (export) data telemetri. Collector sangat krusial di lingkungan produksi karena mengurangi beban jaringan aplikasi, melakukan batching, kompresi, dan menyaring data sensitif sebelum dikirim ke penyimpanan jangka panjang.
  3. Context Propagation: Mekanisme penyisipan metadata (seperti traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01) melalui protokol HTTP/gRPC headers, memungkinkan layanan downstream mengetahui konteks parent span dari hulu.

3. Perbandingan Komparatif / Analisis Pendekatan

Dalam mendesain infrastruktur pengumpulan data, arsitek dihadapkan pada dua pola penempatan OpenTelemetry Collector:

Aspek Perbandingan Pola Agent (Daemonset / Sidecar) Pola Gateway (Centralized Cluster)
Deployment Dijalankan di setiap node Kubernetes atau sebagai sidecar di setiap container/server. Dijalankan sebagai klaster terpusat tersendiri di dalam jaringan internal.
Network Overhead Sangat rendah. Aplikasi mengirim data secara lokal (localhost:4317). Sedang hingga tinggi. Aplikasi mengirim data melintasi jaringan ke endpoint pusat.
Resource Footprint Konsumsi RAM dan CPU terdistribusi di setiap node (skala kecil per node). Konsumsi sumber daya tinggi terkonsentrasi pada klaster collector pusat.
Keamanan & Filtering Memungkinkan sanitasi data sensitif (PII/Masking) paling dekat dengan sumbernya. Pemrosesan terpusat, memudahkan pembaruan aturan keamanan secara global.
Rekomendasi Penggunaan Sistem skala besar, multi-cloud, atau arsitektur mikroservis kompleks. Infrastruktur skala kecil hingga menengah dengan manajemen terpusat.

[!IMPORTANT] Untuk lingkungan produksi berskala enterprise, Pola Hibrida (Agent lokal untuk batching awal dan Gateway terpusat untuk routing akhir ke storage) adalah standar industri terbaik untuk menghindari saturasi jaringan.

4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum melakukan implementasi teknis, pastikan spesifikasi infrastruktur dan dependensi berikut telah terpenuhi dengan baik:

  • OS: Ubuntu 22.04 LTS / Debian 12 / AlmaLinux 9 (Kernel Linux >= 5.10)
  • Runtime & Bahasa: Go 1.21+, Node.js 18+ LTS, PHP 8.2+ (dengan ekstensi OTel), Nginx 1.24+
  • Backend Observability: Grafana Tempo (Tracing), Prometheus (Metrics), Grafana Loki (Logs)
  • Port Jaringan yang Harus Dibuka:
    • 4317 (gRPC OTLP Receiver)
    • 4318 (HTTP OTLP Receiver)
    • 8889 (Prometheus Metrics Exporter dari Collector)

Lakukan verifikasi awal paket sistem dan direktori kerja:

sudo mkdir -p /etc/otelcol /var/log/otel
sudo groupadd -f otel
sudo useradd -g otel -s /sbin/nologin otel

5. Panduan Implementasi Langkah demi Langkah

Langkah 1: Konfigurasi OpenTelemetry Collector (/etc/otelcol/config.yaml)

Buat file konfigurasi lengkap untuk OTel Collector yang bertindak sebagai penerima, pemroses, dan pengirim data ke backend (Prometheus dan Grafana Tempo).

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  memory_limiter:
    check_interval: 1s
    limit_percentage: 80
    spike_limit_percentage: 20
  batch:
    send_batch_size: 1024
    timeout: 5s
    send_batch_max_size: 2048

exporters:
  prometheus:
    endpoint: "0.0.0.0:8889"
    namespace: "enterprise"
  otlp/tempo:
    endpoint: "tempo-backend.internal:4317"
    tls:
      insecure: true

extensions:
  health_check:
    endpoint: 0.0.0.0:13133
  zpages:
    endpoint: 0.0.0.0:55679

service:
  extensions: [health_check, zpages]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp/tempo]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [prometheus]
  telemetry:
    logs:
      level: "info"

Langkah 2: Sistemd Service untuk OTel Collector (/etc/systemd/system/otelcol.service)

[Unit]
Description=OpenTelemetry Collector Enterprise Daemon
After=network.target

[Service]
User=otel
Group=otel
ExecStart=/usr/local/bin/otelcol --config=/etc/otelcol/config.yaml
Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Aktifkan dan jalankan servis:

sudo systemctl daemon-reload
sudo systemctl enable --now otelcol
sudo systemctl status otelcol

Langkah 3: Instrumentasi Backend Golang (Go Web Service)

Berikut adalah contoh implementasi pada server HTTP Go yang melakukan inisialisasi SDK OpenTelemetry dan meneruskan konteks ke database MySQL.

package main

import (
	"context"
	"database/sql"
	"log"
	"net/http"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
)

func initTracer(ctx context.Context) (*sdktrace.TracerProvider, error) {
	exporter, err := otlptracegrpc.New(ctx,
		otlptracegrpc.WithInsecure(),
		otlptracegrpc.WithEndpoint("localhost:4317"),
	)
	if err != nil {
		return nil, err
	}

	res, err := resource.New(ctx,
		resource.WithAttributes(
			semconv.ServiceNameKey.String("auth-service-go"),
			semconv.ServiceVersionKey.String("1.2.0"),
		),
	)
	if err != nil {
		return nil, err
	}

	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithResource(res),
		sdktrace.WithSampler(sdktrace.AlwaysSample()),
	)

	otel.SetTracerProvider(tp)
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
		propagation.TraceContext{},
		propagation.Baggage{},
	))

	return tp, nil
}

func main() {
	ctx := context.Background()
	tp, err := initTracer(ctx)
	if err != nil {
		log.Fatalf("Failed to init tracer: %v", err)
	}
	defer func() {
		if err := tp.Shutdown(ctx); err != nil {
			log.Printf("Error terminating TracerProvider: %v", err)
		}
	}()

	db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/app_db?parseTime=true")
	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		tr := otel.Tracer("auth-service-handler")
		ctx, span := tr.Start(r.Context(), "ProcessAuthentication")
		defer span.End()

		// Simulasi kueri database dengan konteks terusan
		var count int
		err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM users").Scan(&count)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		time.Sleep(50 * time.Millisecond)
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`{"status":"authenticated\
🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server