Mert Tosun
← Yazılar
OpenTelemetry ile Go Servislerinde Distributed Tracing

OpenTelemetry ile Go Servislerinde Distributed Tracing

Mert TosunObservability

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:

  1. Tracer provider oluşturulur
  2. Exporter (OTLP) tanımlanır
  3. 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ı.