OpenTelemetry ile Go Servislerinde Distributed Tracing
Mikroservis mimarisinde bir isteğin neden yavaşladığını sadece loglardan anlamak zorlaşır.
Çünkü akış, API gateway'den başlayıp birden fazla servis, queue ve veritabanına dağılır.
Burada distributed tracing, isteğin her adımını tek bir zincirde görmeyi sağlar.
Bu yazıda Go servislerinde OpenTelemetry kurulumunu ve production'da gerçekten işe yarayan pratikleri inceleyeceğiz.
1) Tracing neden gerekli?
Metrix size "sorun var" der, tracing size "sorun nerede"yi gösterir.
Örnek soru seti:
- P95 latency neden arttı?
- Gecikme auth servisinde mi, DB'de mi?
- Retry döngüsü hangi endpoint'te patlıyor?
Trace olmadan bu sorular genelde tahminle çözülür.
2) Temel kavramlar
- Trace: Bir isteğin uçtan uca hikayesi
- Span: Bu hikayedeki tek adım (HTTP call, DB query, cache lookup)
- Context propagation: Trace id'nin servisler arası taşınması
Her span'ın süresi, status'u ve attribute'ları vardır.
Böylece sadece "yavaş" değil, "neden yavaş" görünür hale gelir.
3) Go servisinde OpenTelemetry başlangıcı
Temel kurulumda:
- Tracer provider oluşturulur
- Exporter (OTLP) tanımlanır
- HTTP middleware ile context taşınır
func initTracer(ctx context.Context) (func(context.Context) error, error) {
exp, err := otlptracegrpc.New(ctx)
if err != nil {
return nil, err
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exp),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName("blog-backend"),
semconv.DeploymentEnvironmentName("production"),
)),
sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(0.1))),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.TraceContext{})
return tp.Shutdown, nil
}
4) Uygulama içinde span üretimi
İş adımlarını anlamlı span'lara ayırın:
func (s *PostService) GetPost(ctx context.Context, slug string) (*Post, error) {
tracer := otel.Tracer("post-service")
ctx, span := tracer.Start(ctx, "GetPost")
defer span.End()
span.SetAttributes(attribute.String("post.slug", slug))
post, err := s.repo.FindBySlug(ctx, slug)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, "repository failure")
return nil, err
}
return post, nil
}
Buradaki kritik nokta: context'in bir üst katmandan gelmesi ve tüm alt çağrılara aktarılması.
5) Sampling stratejisi: hepsini toplamak şart değil
%100 sampling üretimde pahalı olabilir.
Pratik model:
- Normal trafik: oran bazlı sampling (örn. %5 - %10)
- Hatalı istekler: öncelikli tutulur
- Kritik endpoint'ler: daha yüksek sampling
ParentBased + TraceIDRatioBased çoğu ekip için iyi başlangıçtır.
6) Attribute ve naming standardı
Dağınık isimlendirme tracing'in değerini düşürür.
Öneriler:
- Span name: kısa ve fiil odaklı (
GetPost,FetchUserProfile) - Attribute key: noktalı isimlendirme (
db.system,http.route,user.id) - Yüksek cardinality alanlardan kaçın (
full_email, rastgele uzun stringler)
Bu disiplin yoksa sorgu performansı ve dashboard kalitesi düşer.
7) Log + metric + trace birlikte düşünülmeli
Tek başına trace yeterli değildir.
Etkili gözlemlenebilirlik:
- Metrik alarmı tetikler
- Trace kök nedeni gösterir
- Log detaylı payload/hata bağlamını verir
Bu üçlüyü aynı trace_id etrafında ilişkilendirmek incident çözüm süresini dramatik kısaltır.
8) Production checklist
- Her giriş noktasında trace context parse ediliyor mu?
- Outbound HTTP/DB client instrument edilmiş mi?
- Sampling oranı maliyet hedefiyle uyumlu mu?
- Trace exporter kesildiğinde uygulama davranışı güvenli mi?
- Hassas veri span attribute olarak yazılmıyor mu?
Sonuç
OpenTelemetry ile distributed tracing, mikroservislerde "karanlıkta debug" dönemini bitirir.
Doğru context propagation ve makul sampling ile hem maliyeti kontrol eder hem de arıza çözüm süresini ciddi şekilde kısaltırsınız.
İlk hedefiniz mükemmel dashboard değil, operasyonel olarak işe yarayan görünürlük olmalı.
İlgili Yazılar
gRPC vs REST: Ne Zaman Hangisini Kullanmalısın? Go ile Karşılaştırmalı Rehber
Mikroservislerde gRPC ve REST farkları; protobuf, HTTP/2, tarayıcı uyumu ve Go örnekleri. REST ile Go servis karşılaştırması için iç link.
Kubernetes'te HPA, VPA ve Cluster Autoscaler: Birlikte Doğru Kullanım
Kubernetes autoscaling katmanlarını (HPA, VPA, Cluster Autoscaler) çakışmadan birlikte çalıştırmak için pratik strateji, metrik seçimi ve production ipuçları.
Go'da Context, Timeout ve Cancellation: Production Dayanıklılık Rehberi
Go servislerinde context propagation, timeout yönetimi, cancellation zinciri ve graceful shutdown pratiklerini gerçek üretim senaryolarıyla anlatan detaylı rehber.