← Kursa Dön
📄 Text · 30 min

Distributed Tracing

Monolitik bir uygulamada bir hata oluştuğunda, tek bir log dosyasına bakarak sorunu bulabilirsiniz. Ancak mikroservis mimarisinde bir istek düzinelerce servisten geçebilir. Hangi serviste hata oluştuğunu, darboğazın nerede olduğunu anlamak için distributed tracing (dağıtık izleme) gereklidir. Bu derste trace ve span kavramlarını, Micrometer Tracing'i, Zipkin entegrasyonunu ve correlation ID propagation'ı öğreneceğiz.

Trace ve Span Kavramları

Trace: Bir isteğin sistemdeki tüm yolculuğunu temsil eden uçtan uca iz. Her trace benzersiz bir traceId'ye sahiptir.

Span: Bir trace içindeki tek bir operasyonu temsil eder. Her span'in kendi spanId'si, başlangıç zamanı ve süresi vardır. Span'ler parent-child ilişkisine sahiptir:

TraceId: abc123
├── Span A: Gateway (root span)         [0ms-250ms]
│   ├── Span B: Order Service           [10ms-200ms]
│   │   ├── Span C: User Service        [20ms-80ms]
│   │   └── Span D: Product Service     [90ms-150ms]
│   └── Span E: Payment Service         [210ms-240ms]

Tüm span'ler aynı traceId'yi paylaşır. Bu sayede bir isteğin tüm servisler arasındaki yolculuğu tek bir trace altında birleştirilir.

Micrometer Tracing Kurulumu

Spring Cloud Sleuth'un yerini alan Micrometer Tracing:

<!-- Micrometer Tracing Bridge -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>

<!-- Zipkin Reporter -->
<dependency>
    <groupId>io.zipkin.reporter2</groupId>
    <artifactId>zipkin-reporter-brave</artifactId>
</dependency>

application.yml:

management:
  tracing:
    sampling:
      probability: 1.0    # %100 örnekleme (prod'da 0.1 = %10)
  zipkin:
    tracing:
      endpoint: http://localhost:9411/api/v2/spans

logging:
  pattern:
    level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"

Bu konfigürasyon ile log çıktıları otomatik olarak traceId ve spanId içerir:

INFO [order-service,abc123def456,789xyz] Processing order #42
INFO [order-service,abc123def456,aaa111] Calling user-service

Correlation ID (İlişkilendirme Kimliği)

Correlation ID, bir isteğe atanan benzersiz kimlik numarasıdır ve isteğin tüm servisler arasındaki yolculuğunu izlemek için kullanılır. Micrometer Tracing'in traceId'si aslında bir correlation ID'dir:

// İstek geldiğinde traceId otomatik oluşturulur
// Her servis çağrısında HTTP header ile propagate edilir:
// traceparent: 00-abc123def456-789xyz-01

Trace Propagation (İz Yayılımı)

Trace bilgisi servisler arasında HTTP header'ları ile yayılır. W3C Trace Context standardı kullanılır:

# W3C Trace Context header
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
#             version-traceId-parentSpanId-flags

Spring Boot bunu otomatik olarak yönetir. RestTemplate, WebClient ve Feign Client üzerinden yapılan çağrılarda trace header'ları otomatik eklenir ve alınır:

// Order Service → User Service çağrısı
// Micrometer otomatik olarak traceparent header'ını ekler
UserDto user = restTemplate.getForObject(
    "http://user-service/api/users/{id}",
    UserDto.class, userId);
// Header: traceparent: 00-abc123-span456-01 → otomatik eklendi

Zipkin

Zipkin, trace verilerini toplamak, depolamak ve görselleştirmek için kullanılan açık kaynak bir platformdur:

# Docker ile Zipkin başlatma
docker run -d -p 9411:9411 openzipkin/zipkin

Zipkin Dashboard (http://localhost:9411) üzerinde:

  • Trace listesi — Tüm trace'leri zaman damgası, süre ve servis adıyla listeler.

  • Trace detayı — Bir trace'in tüm span'lerini waterfall (şelale) grafiğinde gösterir.

  • Dependency grafiği — Servislerin birbirleriyle iletişim haritasını çizer.

Özel Span Oluşturma

Otomatik span'lere ek olarak, kendi span'lerinizi oluşturabilirsiniz:

@Service
public class OrderService {

    private final Tracer tracer;

    public OrderService(Tracer tracer) {
        this.tracer = tracer;
    }

    public Order processOrder(OrderRequest request) {
        // Özel span başlat
        Span inventorySpan = tracer.nextSpan()
            .name("check-inventory")
            .tag("product.id", request.getProductId().toString())
            .start();

        try (Tracer.SpanInScope ws =
                tracer.withSpan(inventorySpan)) {
            // Envanter kontrolü
            boolean available = inventoryService.check(
                request.getProductId(), request.getQuantity());

            inventorySpan.tag("inventory.available",
                String.valueOf(available));

            if (!available) {
                inventorySpan.tag("error", "out of stock");
                throw new OutOfStockException();
            }

            return createOrder(request);
        } finally {
            inventorySpan.end();
        }
    }
}

@Observed Annotation

Spring Boot 3'te Micrometer Observation API ile daha temiz span oluşturma:

@Service
public class PaymentService {

    @Observed(name = "payment.process",
              contextualName = "process-payment",
              lowCardinalityKeyValues = {"payment.type", "credit-card"})
    public PaymentResult processPayment(PaymentRequest request) {
        // Bu metot otomatik olarak bir span oluşturur
        // Süre, başarı/hata durumu otomatik kaydedilir
        return gateway.charge(request);
    }
}

Distributed tracing, mikroservis mimarisinde observability'nin temel direğidir. Production'da sampling oranını %10-20'de tutun, trace tag'lerine hassas bilgi eklemeyin ve Elasticsearch backend ile uzun süreli saklama yapın.