Gece saat 03.00’te uykulu bir şekilde mesaiye başlayan ekip, ekranlarda hızla kayan binlerce hata mesajıyla karşılaşıyor. Tüm loglar "Bağlantı zaman aşımı" hatasıyla dolu. Zaman damgaları yoğun, istek yolları belirsiz, ancak hangi hizmetteki hangi çağrının arızaya yol açtığını anlamak içinse hiçbir ipucu yok. Aslında sorun log kalitesinde değil; logların yapısal bir sınırlaması var. Doğru birimi kullanmadığınız sürece, ne kadar iyi loglama yapsanız da çözüm elde edemiyorsunuz. O doğru birim ise izlemedir.
Log’un sınırları: Neden yeterli değil?
Yapılandırılmış bir log satırı, "Bu hizmet bu anda ne gözlemledi?" sorusuna yanıt verir. Ancak bu yanıt, yalnızca hizmetin o anki durumuna odaklanır. Log satırı, hizmetin bulunduğu bağlamdan bağımsız, yerel bir kaynaktır. Monolitik sistemlerde bu sınırlama tolere edilebilir — tüm istek tek bir işlemde yürütülür, loglar ortak bir bellek içinde yer alır ve request_id gibi bir alanla sonradan ilişkisel sorgulama yapılabilir.
Mikro hizmet mimarisinde ise durum tamamen değişir. Bir kullanıcı isteği, Kubernetes giriş noktasından başlayıp yanıt alıncaya kadar beş ila yirmi farklı iç hizmeti dolaşabilir: kimlik doğrulama geçidi, oturum çözümleme servisi, alan API’leri, özellik bayrak katmanı, veri tabanı çağrıları, öneri motoru ve fatura servisi. Her hizmet kendi loglarını farklı bir kaynağa, farklı bir formata yazar. Bu da isteklerin zincirini anlamayı neredeyse imkansız hale getirir. Loglar, isteklerin izini sürmek için yeterli değildir; çünkü izlemek için gereken çağrı grafiği bilgisine sahip değillerdir.
İzlemenin gücü: Olayları bir bütün olarak görmek
Bir iz, tek bir isteğin tüm sistemdeki yolculuğunu kaydeder. Bu, span adı verilen birimlerden oluşan bir ağaç yapısıdır. Her span, bir hizmet çağrısı, veritabanı sorgusu, önbellek erişimi veya dış HTTP isteği gibi bir iş birimini temsil eder. Span’lar arasındaki ebeveyn-çocuk ilişkileri, çağrıların hiyerarşisini korur. İz, bir trace_id ile tanımlanır ve bu kimlik, isteklerin tüm yolu boyunca taşınır.
İz’ler görselleştirildiğinde, bir su şelalesi gibi görünür: yatay eksen zamanı, dikey eksen hizmetleri ve işlemleri temsil eder. Her span, süresi kadar genişleyen bir renkli çubuktur. Yavaş olan span geniş, hatalı olan span ise kırmızıdır. Artık 20 farklı grep komutu yerine, tek bir ekranda tüm yanıtlar bulunabilir: Hangi hizmette gecikme var? Hangi çağrıda hata meydana geldi?
Bu, loglama seviyesinde yapılan bir iyileştirme değildir. İzleme, logların sunduğu anlık durumu değil, isteğin bütünsel yolculuğunu kaydeder. Loglar hizmet bazında akarken, izler istek bazında bütünlüğü sağlar. İkisi birbirini tamamlar, ancak yerini alamaz.
Standartlaşma çağı: OpenTelemetry ve W3C Trace Context
Dağıtık izleme, aslında yeni bir kavram değil. Google’ın 2010 yılında yayınladığı Dapper makalesi, bu alanın temelini attı. Twitter, 2012 yılında Zipkin’i, Uber ise 2017 yılında Jaeger’ı açık kaynak olarak yayınladı. Ancak yıllarca, izleme genellikle satıcıya özel SDK’larla sınırlı kaldı. Uygulamaları izlemek, bir APM aracına bağlı kalmak anlamına geliyordu.
Bu durum, iki önemli standartla değişti:
- W3C Trace Context (6 Şubat 2020): HTTP hizmetleri arasında iz kimliklerini aktarmak için satıcıdan bağımsız bir
traceparentbaşlığı tanımladı. Bu başlık, iz kimliği, ebeveyn span kimliği ve örnekleme bayraklarını içerir. Artık çoğu HTTP istemcisi ve çerçevesi bu standardı destekliyor. - OpenTelemetry (Mayıs 2019 - CNCF Sandbox, Ağustos 2021 - Incubating): OpenTracing ve OpenCensus projelerinin birleşimi olan OpenTelemetry, çoğu programlama diline (Node.js, Python, Java, Go, .NET, Rust, Ruby, PHP) destek sunan bir SDK koleksiyonu sunar. OTLP protokolüyle çalışan bir Toplayıcı bileşeni, uygulama tarafındaki enstrümantasyonu herhangi bir arka uca yönlendirir.
OpenTelemetry’in en büyük avantajı, otomatik enstrümantasyon özelliğidir. HTTP sunucuları, ORM’ler, RPC istemcileri ve mesaj kuyruğu kütüphaneleri, kod değişikliği yapmadan otomatik olarak izlenebilir hale gelir. Bu da 2010’ların "bir APM’e bağlan ve SDK’larını kullan" yaklaşımını tarihe gömmüştür. Artık geliştiriciler, uygulamalarını enstrümantasyonla donatır ve verileri istedikleri arka uca yönlendirebilir.
İzlemeyi kullanmaya başlamak için 3 adım
- Enstrümantasyonu seç: Uygulamanızın diline uygun OpenTelemetry SDK’sını yükleyin. Örneğin, Python için:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
# İzleyiciyi başlat
trace.set_tracer_provider(TracerProvider())
# Verileri topluca göndermek için bir işlemci oluştur
exporter = OTLPSpanExporter(endpoint=")
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(exporter))- Bağlantıyı kur: İzleyicinin verilerini göndereceği arka uca (örneğin, Jaeger, Grafana Tempo, Datadog) yönlendirin. OpenTelemetry’in Toplayıcı bileşeni, uygulamalarınızın enstrümantasyonunu destekleyen herhangi bir arka uçla entegre olabilir.
- Verileri analiz et: İzleme aracınızın su şelalesi görünümünde, yavaş ve hatalı span’ları belirleyin. Örneğin, bir API çağrısının neden 5 saniyeden uzun sürdüğünü veya bir veritabanı sorgusunun nerede tıkandığını anında görebilirsiniz.
Sonuç: İzleme, geleceğin izleme aracı
Loglar, sistemlerin anlık durumunu kaydetmek için değerli olmaya devam edecek. Ancak karmaşık mikro hizmet mimarilerinde, olayların neden ve nasıl meydana geldiğini anlamak için loglar yeterli değil. İzleme, olayların bütünsel yolculuğunu kaydeder ve geliştiricilere, operasyon ekiplerine ve veri bilimcilere, sistemlerin davranışını daha derinlemesine analiz etme olanağı sunar.
OpenTelemetry ve W3C Trace Context gibi standartların yaygınlaşmasıyla, izleme artık satıcıya bağlı bir lüks değil, tüm sistemlerin temel bir bileşeni haline geldi. Gelecekte, mikro hizmet mimarilerinin karmaşıklığı arttıkça, izlemenin değeri de daha da artacak. Loglarınızın ötesine geçmek ve sistemlerinizin gerçek hikayesini anlamak için, bugün izlemeyi uygulamaya başlamanın tam zamanı.
Yapay zeka özeti
Discover why traditional logs fall short in distributed systems and how distributed tracing provides the missing context to debug failures and latency in microservices.