L
Observability & Monitoring • Literally Web ID

Distributed Tracing & Observability: Implementasi OpenTelemetry dan Prometheus pada Sistem Microservices

⏱️ 18 menit baca • 📅 12 Oct 2026 • 👁️ 1 views
Distributed Tracing & Observability: Implementasi OpenTelemetry dan Prometheus pada Sistem Microservices

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap arsitektur web modern yang beralih dari monolith monolitik menuju sistem microservices terdistribusi, kompleksitas operasional meningkat secara eksponensial. Sebuah satu klik tombol pada aplikasi front-end berbasis Single Page Application (SPA) yang di-serve melalui CDN Cloudflare dapat memicu puluhan bahkan ratusan panggilan jaringan internal lintas bahasa pemrograman (Go, Node.js, PHP-FPM), melewati reverse proxy Nginx, mengantri di Redis, hingga berinteraksi dengan klaster database MySQL/MariaDB yang di-host secara terpisah.

Analisis Akar Masalah Bottleneck Performa

Ketika terjadi latensi tinggi atau kegagalan sistem (500 Internal Server Error), administrator infrastruktur dan Site Reliability Engineer (SRE) sering kali dihadapkan pada masalah klasik: Blind Troubleshooting. Mengandalkan log berbasis teks konvensional tanpa konteks lintas layanan (Distributed Context) mengakibatkan:

  1. Isolation of Logs: Log aplikasi Node.js tidak memiliki korelasi dengan log backend Go, menyulitkan pelacakan Root Cause.
  2. Metric Blindness: Metrik penggunaan CPU dan memori dari Prometheus berdiri sendiri tanpa kaitan langsung dengan transaksi bisnis yang sedang melambat.
  3. Lack of Traceability: Permintaan masuk dari klien tidak memiliki pengenal unik (Trace ID) yang konsisten melintasi batas jaringan, protokol, dan antrian pesan seperti RabbitMQ atau Kafka.

Kondisi Sebelum vs Sesudah Penerapan Observability Menyeluruh

  • Sebelum: Waktu resolusi insiden (Mean Time to Resolution - MTTR) mencapai jam bahkan hari. Tim harus melakukan grep manual pada file log di berbagai server, menebak-nebak layanan mana yang mengalami kegagalan, dan melakukan restarting membabi buta pada Nginx atau PHP-FPM.
  • Sesudah: Penerapan OpenTelemetry sebagai standar unifikasi pengumpulan sinyal telemetri (Traces, Metrics, Logs) dipadu dengan Prometheus untuk time-series metrics dan Grafana untuk visualisasi terpusat. MTTR merosot tajam menjadi hitungan menit. Setiap request dapat dilacak secara visual dari edge hingga baris query SQL terdalam.

[!IMPORTANT] Observability bukanlah sekadar monitoring. Monitoring memberi tahu Anda kapan sistem rusak, sementara Observability memberi tahu Anda mengapa sistem tersebut rusak.


2. Konteks Inti & Deep Dive Arsitektur

Untuk memahami cara kerja OpenTelemetry (OTel) dan Prometheus secara mendalam, kita harus membedah konsep Three Pillars of Observability: Metrics, Traces, dan Logs, serta bagaimana ketiganya diikat oleh Context Propagation.

Arsitektur Alur Data OpenTelemetry & Prometheus

+---------------------------------------------------------------------------------+
|                              Client / Browser (SPA)                             | 
+---------------------------------------------------------------------------------+
                                         |
                                         v
+---------------------------------------------------------------------------------+
|                        Cloudflare CDN & Edge Caching                            |
+---------------------------------------------------------------------------------+
                                         |
                                         v
+---------------------------------------------------------------------------------+
|                Nginx Reverse Proxy & Load Balancer (WAF / SSL)                  |
+---------------------------------------------------------------------------------+
                 |                                               |
                 v                                               v
+-----------------------------------+   +-----------------------------------------+
|      Microservice A (Go)          |   |       Microservice B (Node.js)          |
|   [OTel SDK Go Instrumentation]     |   |     [OTel SDK Node Instrumentation]       |
+-----------------------------------+   +-----------------------------------------+
                 |                                               |
                 +-----------------------+-----------------------+
                                         |
                                         v
+---------------------------------------------------------------------------------+
|                       OpenTelemetry Collector (OTel Collector)                  | 
+---------------------------------------------------------------------------------+
             |                                                       |
             v (Push: OTLP gRPC)                                     v (Pull: Prometheus Exporter)
+---------------------------------------+   +-------------------------------------+
|         Grafana Tempo (Traces)        |   |         Prometheus (Metrics)        |
+---------------------------------------+   +-------------------------------------+
             |                                                       |
             +-----------------------+-----------------------+
                                         |
                                         v
+---------------------------------------------------------------------------------+
|                        Grafana Dashboards (Unified UI)                          |
+---------------------------------------------------------------------------------+

Penjelasan Alur Eksekusi (Under the Hood)

  1. Context Propagation: Ketika request HTTP masuk ke Nginx, header W3C Trace Context (traceparent dan tracestate) diinjeksikan atau diteruskan. Jika belum ada, Nginx atau Edge Worker akan mengenerate Trace ID baru.
  2. Instrumentation SDK: Layanan berbasis Go atau Node.js menerima header tersebut, mengekstrak konteks, dan membuat Span baru yang menjadi bagian dari Trace yang sama.
  3. Telemetry Export: SDK mengirimkan data traces dan metrics ke OpenTelemetry Collector menggunakan protokol OTLP (OpenTelemetry Protocol) baik via gRPC (port 4317) maupun HTTP (port 4318).
  4. Storage & Scraping: Prometheus melakukan scrape endpoint /metrics dari OTel Collector atau aplikasi secara langsung, sementara data traces diteruskan ke backend penyimpanan seperti Grafana Tempo atau Jaeger.

3. Perbandingan Komparatif / Analisis Pendekatan

Tabel di bawah ini membandingkan pendekatan tradisional dengan pendekatan berbasis OpenTelemetry dan Prometheus dalam arsitektur sistem enterprise.

Parameter Komparasi Pendekatan Tradisional (Log Manual & APM Komersial) OpenTelemetry & Prometheus (Standar Open Source) Dampak & Trade-off Infrastruktur
Vendor Lock-in Tinggi (Terikat agen proprietary APM komersial) Nol (Vendor-agnostic, standar industri CNCF) Fleksibilitas migrasi backend penyimpanan tinggi.
Overhead Memori & CPU Variatif, sering kali membebani runtime aplikasi Sangat optimal, overhead CPU < 2%, RAM terkontrol Memerlukan tuning buffer OTel Collector yang tepat.
Standarisasi Format Berbeda di tiap bahasa (Go, Node.js, PHP) Seragam menggunakan spesifikasi W3C Trace Context Mempermudah korelasi lintas bahasa pemrograman.
Biaya Lisensi Biaya berlangganan per host/GB data sangat mahal Gratis (Open Source), hanya biaya infrastruktur Efisiensi biaya operasional jangka panjang meningkat.
Kompleksitas Setup Cepat di awal, sulit dikustomisasi di kemudian hari Membutuhkan pemahaman arsitektur yang mendalam Kurva belajar awal tim SRE lebih tinggi.

4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum melakukan implementasi teknis, pastikan spesifikasi lingkungan server dan dependensi berikut telah terpenuhi:

  • Sistem Operasi: Ubuntu 22.04 LTS / Debian 12 Bookworm.
  • Runtime & Bahasa:
    • Go version 1.21+
    • Node.js version 18.x LTS / 20.x LTS
  • Infrastruktur Pendukung:
    • Prometheus v2.45+
    • OpenTelemetry Collector Contrib v0.90+
    • Grafana v10.x
  • Izin & Akses: Akses sudo / root pada server, serta port jaringan yang terbuka:
    • 9090 (Prometheus)
    • 4317 (OTLP gRPC)
    • 4318 (OTLP HTTP)
    • 3000 (Grafana)

Verifikasi Awal Sistem

Jalankan perintah berikut pada terminal untuk memastikan versi pustaka dan ketersediaan port:

go version
node -v
prometheus --version

5. Panduan Implementasi Langkah demi Langkah

Langkah 1: Konfigurasi OpenTelemetry Collector (otel-collector-config.yaml)

Buat file konfigurasi untuk OTel Collector yang bertindak sebagai agen penerima data telemetri dari aplikasi Go dan Node.js.

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

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

exporters:
  prometheus:
    endpoint: "0.0.0.0:8889"
    namespace: "enterprise"
  logging:
    verbosity: detailed

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [logging]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [prometheus, logging]

Langkah 2: Instrumentasi Aplikasi Backend Go

Implementasikan OpenTelemetry pada aplikasi backend Go untuk mencatat traces dan custom metrics.

package main

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

	"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"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func initTracer(ctx context.Context) (*sdktrace.TracerProvider, error) {
	res, err := resource.New(ctx,
		resource.WithAttributes(
			semconv.ServiceNameKey.String("auth-service-go"),
			semconv.ServiceVersionKey.String("1.0.0"),
		),
	)
	if err != nil {
		return nil, err
	}

	conn, err := grpc.DialContext(ctx, "localhost:4317", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
	if err != nil {
		return nil, err
	}

	exporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithGRPCConn(conn))
	if err != nil {
		return nil, err
	}

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

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

	return tp, nil
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
	tr := otel.Tracer("auth-service-tracer")
	ctx, span := tr.Start(r.Context(), "HTTP GET /api/v1/auth")
	defer span.End()

	time.Sleep(50 * time.Millisecond) // Simulasi latensi database/query
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"status": "authenticated"}`))
}

func main() {
	ctx := context.Background()
	tp, err := initTracer(ctx)
	if err != nil {
		log.Fatalf("Gagal inisialisasi tracer: %v", err)
	}
	defer func() {
		if err := tp.Shutdown(ctx); err != nil {
			log.Printf("Error saat shutdown tracer: %v", err)
		}
	}()

	http.HandleFunc("/api/v1/auth", helloHandler)
	log.Println("Auth Service Go berjalan pada port 8080...")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}

Langkah 3: Instrumentasi Aplikasi Backend Node.js

Buat file inisialisasi tracing untuk layanan Node.js (tracing.js) sebelum menjalankan aplikasi utama.

'use strict';

const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');

const traceExporter = new OTLPTraceExporter({
  url: 'http://localhost:4317',
});

const sdk = new NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'payment-service-node',
    [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',
  }),
  traceExporter,
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start()
  .then(() => console.log('OpenTelemetry SDK Node.js berhasil diinisialisasi.'))
  .catch((error) => console.log('Error inisialisasi OTel SDK Node.js:', error));

process.on('SIGTERM', () => {
  sdk.shutdown()
    .then(() => console.log('OpenTelemetry SDK berhasil dihentikan.'))
    .catch((error) => console.log('Error saat menghentikan SDK:', error))
    .finally(() => process.exit(0));
});

Langkah 4: Konfigurasi Prometheus (prometheus.yml)

Konfigurasikan Prometheus untuk mengambil metrik dari aplikasi dan OpenTelemetry Collector.

global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets: []

rule_files:
  - "alert_rules.yml"

scrape_configs:
  - job_name: 'otel-collector'
    static_configs:
      - targets: ['localhost:8889']
  
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

6. Bedah Kode & Penjelasan Detail Baris Kunci

  • propagation.NewCompositeTextMapPropagator pada Go: Berfungsi menggabungkan standar W3C Trace Context (traceparent) dan Baggage. Baris ini memastikan bahwa Trace ID dan Span ID dapat diteruskan melalui header HTTP dari layanan Go ke Node.js tanpa terputus.
  • memory_limiter pada OTel Collector: Pengaturan krusial untuk mencegah Out-Of-Memory (OOM) Killer pada server Collector. Jika penggunaan memori mencapai 80%, proses batching akan diperketat untuk menghindari crash sistem saat lonjakan traffic (traffic spikes).
  • getNodeAutoInstrumentations() pada Node.js: Mengaktifkan auto-instrumentation untuk pustaka populer seperti Express, HTTP, gRPC, dan MySQL tanpa perlu mengubah baris kode bisnis secara manual.

7. Skenario Produksi & Studi Kasus Dunia Nyata

Pada sistem E-Commerce High Concurrency dengan 50.000 request per detik (RPS), latensi mendadak melonjak pada halaman Checkout.

Investigasi Menggunakan OpenTelemetry & Grafana

  1. Identifikasi Anomali: SRE melihat grafik latensi p99 melonjak dari 150ms menjadi 3.2 detik pada dashboard Prometheus.
  2. Pencarian Trace: SRE memasukkan Trace ID yang gagal pada Grafana Tempo. Visualisasi menunjukkan bahwa bottleneck bukan pada layanan payment-service-node, melainkan pada pemanggilan database MySQL eksternal melalui query SELECT * FROM inventory WHERE product_id = ? yang tidak memiliki index.
  3. Resolusi: Tim DBA segera menambahkan composite index pada tabel tersebut, dan latensi kembali normal dalam kurun waktu kurang dari 5 menit.

8. Common Pitfalls, Anti-Patterns & Solusi

  • Anti-Pattern 1: 100% Sampling Rate di Production
    • Masalah: Mengambil seluruh data traces (100% sampling) pada sistem dengan beban jutaan RPS akan menghabiskan ruang penyimpanan storage secara masif dan membebani jaringan.
    • Solusi: Gunakan Head-based sampling dengan rate 1% hingga 5% untuk traffic normal, dan gunakan Tail-based sampling pada OTel Collector untuk hanya menyimpan traces yang mengalami error atau latensi tinggi (>1000ms).
  • Anti-Pattern 2: Mengabaikan Label Cardinality pada Prometheus
    • Masalah: Menjadikan parameter unik seperti User ID atau Email sebagai label metrik di Prometheus akan menyebabkan TimeSeries explosion dan membuat server Prometheus kehabisan RAM.
    • Solusi: Batasi label hanya pada dimensi diskrit dengan kardinalitas rendah seperti status_code, method, atau service_name.

9. Benchmark, Metrik Kinerja & Tuning Performa

Untuk menguji ketahanan infrastruktur observability, lakukan load testing menggunakan tool k6:

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 100 },
    { duration: '1m', target: 500 },
    { duration: '30s', target: 0 },
  ],
};

export default function () {
  const res = http.get('http://localhost:8080/api/v1/auth');
  check(res, { 'status adalah 200': (r) => r.status === 200 });
  sleep(1);
}

Tuning Lanjutan OTel Collector

Tingkatkan ukuran queue pada prosesor batch jika terjadi dropped spans pada log sistem:

processors:
  batch:
    send_batch_size: 8192
    timeout: 500ms
    send_batch_max_size: 16384

10. Checklist Penerapan Produksi & Kesimpulan

Sebelum meluncurkan arsitektur OpenTelemetry dan Prometheus ke lingkungan produksi, pastikan checklist berikut telah terpenuhi sepenuhnya:

  • Sampling rate traces telah diatur dengan bijak (tidak 100% di production).
  • Kardinalitas label Prometheus telah diverifikasi aman dari TimeSeries explosion.
  • Memory limiter aktif pada OpenTelemetry Collector untuk mencegah OOM.
  • Header W3C Trace Context diteruskan dengan benar melalui Nginx ke seluruh microservices.
  • Dashboard Grafana dan aturan Alerting telah diuji dengan simulasi chaos engineering.

Dengan implementasi yang disiplin, OpenTelemetry dan Prometheus tidak hanya memberikan visibilitas penuh ke dalam jeroan sistem terdistribusi, tetapi juga mentransformasi tim SRE dari mode reaktif menjadi proaktif dalam menjaga keandalan infrastruktur enterprise.

🏷️ Tags: #Golang #Microservices #Opentelemetry #Prometheus #Distributed Tracing