Distributed Tracing
Versi Bahasa Indonesia. Baca dalam Bahasa Inggris
Distributed tracing adalah teknik yang digunakan untuk melacak permintaan saat mengalir melalui berbagai layanan dalam arsitektur microservices atau sistem terdistribusi. Ini membantu memberikan visibilitas tentang bagaimana permintaan diproses, bagaimana layanan berinteraksi, dan di mana bottleneck atau kegagalan mungkin terjadi.
Konsep Utama
- Trace: Mewakili perjalanan sebuah permintaan saat bergerak melalui sistem. Satu trace terdiri dari beberapa span.
- Span: Mewakili satu unit kerja atau operasi dalam sebuah layanan (misalnya, query database atau panggilan HTTP). Berisi metadata seperti:
- Waktu mulai
- Durasi
- Nama operasi
- Tags (misalnya, status, pesan error)
- Trace Context: Metadata yang menghubungkan semua span bersama. Ini mencakup informasi seperti trace ID, span ID, parent span ID, dan informasi kontekstual lainnya seperti timestamp.
- Hubungan Parent-Child: Span sering diatur dalam struktur pohon di mana satu span (parent) memicu atau memanggil span lain (children), membentuk hierarki. Hubungan parent-child ini mewakili bagaimana layanan berinteraksi selama siklus hidup sebuah permintaan.
- Sampling: Untuk menghindari overhead, sistem tracing dapat mengambil sampel subset permintaan untuk dilacak. Tidak semua permintaan dilacak, dan sampling memungkinkan pelacakan efisien atas permintaan penting atau acak.
Cara Kerja Distributed Tracing
- Inisiasi Permintaan: Saat permintaan masuk ke sistem, trace ID unik dibuat untuk mewakili permintaan tersebut. Setiap layanan atau microservice yang menangani permintaan ini menambahkan span ke trace.
- Pembuatan Span: Setiap layanan yang memproses permintaan membuat span-nya sendiri, mencatat metadatanya (misalnya, waktu mulai, waktu selesai, nama layanan), dan menyebarkan trace context (trace ID, span ID) ke layanan atau sistem berikutnya.
- Propagasi Konteks: Saat permintaan berjalan melalui berbagai microservice, trace context (trace ID, parent span ID) diteruskan bersama permintaan, sehingga sistem dapat terus membangun trace di layanan lain.
- Finalisasi: Setelah permintaan selesai (atau gagal), layanan terakhir menandai akhir trace, dan semua span dikirim ke backend tracing untuk agregasi dan visualisasi.
Correlation ID vs Trace ID
- Correlation ID:
- Pengidentifikasi generik yang digunakan terutama untuk log.
- Berfokus pada mengidentifikasi dan melacak permintaan dalam log.
- Trace ID:
- Pengidentifikasi spesifik yang digunakan dalam sistem distributed tracing.
- Berfokus pada menghubungkan span dan mewakili aliran permintaan di seluruh layanan.
Saling Melengkapi
Meskipun istilah-istilah ini terkait, keduanya memiliki tujuan yang sedikit berbeda. Namun, correlation ID dapat melengkapi trace ID, terutama di sistem yang belum sepenuhnya menerapkan tracing.
- Bahkan dengan distributed tracing, log dari berbagai layanan mungkin tidak secara otomatis menyertakan Trace ID.
- Dengan menambahkan Correlation ID secara eksplisit di log, Anda menciptakan tampilan terpadu dari aliran permintaan di seluruh log dan trace.
- Correlation ID dapat melengkapi trace ID, terutama di sistem yang belum sepenuhnya menerapkan tracing.
- Correlation ID dapat melayani kebutuhan pelacakan khusus, seperti menghubungkan peristiwa yang tidak dapat dilacak (misalnya, pemrosesan pesan asinkron) ke permintaan asli.
- Data trace mungkin tidak tersedia jika infrastruktur tracing gagal atau span dihilangkan karena sampling. Correlation ID dalam log memastikan Anda masih memiliki cadangan untuk debugging.
Tools Umum
- Jaeger
- OpenTelemetry
- Grafana Tempo
- AWS X-Ray
- Google Cloud Trace
Use Case
- Pemantauan Kinerja
- Deteksi Error dan Debugging
- Pemetaan Dependency Layanan
- Rincian Latensi Permintaan
- Analisis Akar Masalah
Contoh
Berikut implementasi untuk menggabungkan Correlation ID dengan Trace ID menggunakan OpenTelemetry di aplikasi Golang.
Bungkus HTTP handler Anda untuk menghasilkan dan menyebarkan Correlation ID jika belum ada:
package main
import (
"context"
"log"
"net/http"
"time"
"github.com/google/uuid"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace"
)
const correlationIDHeader = "X-Correlation-ID"
func initTracer() func() {
exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint())
if err != nil {
log.Fatalf("failed to initialize stdout exporter: %v", err)
}
resource := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("example-service"),
)
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource),
)
otel.SetTracerProvider(tp)
return func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
tp.Shutdown(ctx)
cancel()
}
}
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
correlationID := r.Header.Get(correlationIDHeader)
if correlationID == "" {
correlationID = uuid.New().String()
r.Header.Set(correlationIDHeader, correlationID)
}
// Tambahkan Correlation ID ke context
ctx := context.WithValue(r.Context(), correlationIDHeader, correlationID)
// Sertakan Trace ID di log untuk korelasi
tracer := otel.Tracer("example-tracer")
ctx, span := tracer.Start(ctx, "request")
defer span.End()
span.SetAttributes(
attribute.String(correlationIDHeader, correlationID),
)
log.Printf("Correlation ID: %s, Trace ID: %s", correlationID, span.SpanContext().TraceID())
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func handler(w http.ResponseWriter, r *http.Request) {
correlationID := r.Context().Value(correlationIDHeader).(string)
traceID := trace.SpanFromContext(r.Context()).SpanContext().TraceID().String()
w.WriteHeader(http.StatusOK)
w.Write([]byte("Correlation ID: " + correlationID + "\n"))
w.Write([]byte("Trace ID: " + traceID + "\n"))
}
func main() {
shutdown := initTracer()
defer shutdown()
mux := http.NewServeMux()
mux.Handle("/", middleware(http.HandlerFunc(handler)))
log.Println("Starting server on :8080")
if err := http.ListenAndServe(":8080", mux); err != nil {
log.Fatalf("server failed: %v", err)
}
}Cara Kerja
- Penanganan Correlation ID:
- Middleware memeriksa keberadaan X-Correlation-ID di header permintaan.
- Jika tidak ada, UUID baru dibuat sebagai Correlation ID.
- Propagasi Konteks:
- Correlation ID ditambahkan ke konteks permintaan untuk penggunaan downstream.
- Integrasi Trace ID:
- Span trace baru dimulai untuk permintaan, dan Trace ID dicatat bersama Correlation ID.
- Span trace secara otomatis dipropagasi ke layanan downstream mana pun.
- Logging:
- Log menyertakan Correlation ID dan Trace ID, memudahkan korelasi antara log dan trace.
Last updated on