Mikroservis Mimarisi & Veri Agregasyonu 4 dk okuma 2 okunma

API Composition Pattern: Birden Çok Servisten Veri Toplama

API Composition Pattern, bir istemcinin tek isteğini karşılamak için birden fazla mikroservisten veri toplayıp birleştiren mimari desendir. Composer bileşeni, paralel çağrılarla gecikmeyi minimize eder, hata toleransı (graceful degradation) ve caching ile dayanıklılık sağlar. BFF katmanı veya GraphQL ile birlikte kullanıldığında, istemciye özel veri agregasyonu sunar.

API Composition Pattern: Birden Çok Servisten Veri Toplama

API Composition Pattern: Birden Çok Servisten Veri Toplama

Mikroservis mimarisinde her servis kendi veritabanına ve sorumluluğuna sahiptir. Ancak bir istemci, genellikle tek bir istekte birden fazla servisten gelen verilere ihtiyaç duyar: sipariş detay sayfası; sipariş, müşteri, ürün ve kargo bilgilerini birlikte gösterir. İşte API Composition Pattern, bu ihtiyacı karşılamak için birden fazla servisten veri toplayıp tek bir yanıtta birleştiren çözümü sunar.


1. API Composition Nedir?

Bir Composer (Birleştirici) bileşeni, istemciden gelen tek bir isteği alır; bu isteği karşılamak için gerekli servislere çağrı yapar ve sonuçları birleştirerek istemciye döner.

text

İstemci → API Composer → [Servis A, Servis B, Servis C]
                ↓
        Birleştirilmiş Yanıt → İstemci

Composer'ın Sorumlulukları:

  • Hangi servislerin çağrılacağını belirlemek.

  • Çağrıları paralel veya sıralı yapmak.

  • Yanıtları birleştirmek (merge/join).

  • Hataları yönetmek (fallback, partial response).

  • Sonucu istemciye uygun formatta dönmek.


2. API Gateway, BFF ve Composition İlişkisi

Desen Amaç Veri Birleştirme Kapsam
API Gateway Tek giriş noktası, routing, auth ❌ Genelde yok Tüm istemciler
BFF İstemciye özel backend ✅ Var Tek istemci türü
API Composition Birden fazla servisten veri toplama ✅ Var (odak) Belirli iş senaryosu

İlişki: API Composition genellikle BFF katmanı içinde uygulanır. BFF, istemciye özel optimizasyon yaparken; Composition, veri toplama mantığını üstlenir.


3. Veri Toplama Stratejileri

A. Paralel Çağrılar (Paralel Composition)

Bağımsız servis çağrıları aynı anda yapılır. Toplam süre, en yavaş servisin süresine eşittir.

csharp

public async Task<OrderDetailDto> GetOrderDetailAsync(int orderId)
{
    var orderTask = _orderService.GetAsync(orderId);
    var customerTask = _customerService.GetByOrderAsync(orderId);
    var itemsTask = _productService.GetItemsAsync(orderId);
    var shipmentTask = _shipmentService.GetByOrderAsync(orderId);

    await Task.WhenAll(orderTask, customerTask, itemsTask, shipmentTask);

    return new OrderDetailDto
    {
        Order = await orderTask,
        Customer = await customerTask,
        Items = await itemsTask,
        Shipment = await shipmentTask
    };
}

Avantaj: Toplam gecikme minimumdur.
Dezavantaj: Servisler arasında bağımlılık varsa uygulanamaz.

B. Sıralı Çağrılar (Sequential Composition)

Bir servisin yanıtı diğeri için gerekliyse sıralı yapılır. Toplam süre, tüm servislerin sürelerinin toplamıdır.

C. Hibrit Yaklaşım (En İyi Pratik)

Bağımsız çağrıları paralel, bağımlı çağrıları sıralı yapın.

csharp

// 1. Siparişi al (bağımsız)
var order = await _orderService.GetAsync(orderId);

// 2. Siparişe bağlı çağrıları paralel başlat
var customerTask = _customerService.GetAsync(order.CustomerId);
var itemsTask = _productService.GetItemsAsync(orderId);
await Task.WhenAll(customerTask, itemsTask);

4. Hata Yönetimi: Dayanıklılık

A. Fail-Fast (Hızlı Başarısız)
Herhangi bir servis çağrısı başarısız olursa tüm istek başarısız olur. Tüm veriler kritikse (ör. ödeme) uygundur.

B. Graceful Degradation (Zarif Bozulma)
Kritik olmayan servisler başarısız olursa kısmi yanıt dönülür.

csharp

var order = await _orderService.GetAsync(orderId);       // Kritik
var items = await _productService.GetItemsAsync(orderId); // Kritik

var customer = await TryGetAsync(() => _customerService.GetAsync(order.CustomerId));
var shipment = await TryGetAsync(() => _shipmentService.GetByOrderAsync(orderId));

// customer/shipment null olabilir; istemci buna göre davranır

C. Polly ile Retry ve Circuit Breaker

csharp

var retryPolicy = Policy
    .Handle<HttpRequestException>()
    .WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1));

var circuitBreaker = Policy
    .Handle<HttpRequestException>()
    .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));

var customer = await retryPolicy.WrapAsync(circuitBreaker)
    .ExecuteAsync(() => _customerService.GetAsync(order.CustomerId));

5. Performans Optimizasyonları

Teknik Açıklama
Paralel çağrılar Bağımsız servisleri Task.WhenAll ile paralel yapın.
Caching Sık kullanılan verileri (müşteri bilgisi) önbelleğe alın.
Batch çağrılar N+1'den kaçının; toplu veri çekin.
Timeout Her çağrıya makul timeout koyun; yavaş servis tüm isteği bloklamasın.

Caching Örneği:

csharp

var customer = await _cache.GetOrSetAsync(
    $"customer:{order.CustomerId}",
    () => _customerService.GetAsync(order.CustomerId),
    TimeSpan.FromMinutes(10));

6. CQRS ve GraphQL ile İlişkisi

CQRS: Okuma tarafında (Query), veriler farklı servislerden toplanarak bir Read Model oluşturulur. API Composition, bu modeli besleyen mekanizmadır.

GraphQL: GraphQL, API Composition için doğal bir çözümdür. Hot Chocolate ile birden fazla kaynağı tek şema altında birleştirebilirsiniz.

csharp

public class Query
{
    public async Task<OrderDetailDto> GetOrderDetail(
        int orderId,
        [Service] IOrderService orderService,
        [Service] ICustomerService customerService)
    {
        var order = await orderService.GetAsync(orderId);
        var customerTask = customerService.GetAsync(order.CustomerId);
        // ...
    }
}

7. Ne Zaman Kullanılmalı?

Uygun Uygun Değil
İstemci tek istekte birden fazla servisten veriye ihtiyaç duyuyorsa Servisler arasında sıkı bağımlılık varsa
Mobil istemciler ağ gecikmesini azaltmak istiyorsa Gerçek zamanlı tutarlılık kritikse
BFF katmanı oluşturuluyorsa Basit CRUD için gereksiz karmaşıklık
Veri toplama mantığı merkezileştirilmek isteniyorsa —

8. En İyi Pratikler

Pratik Açıklama
Paralel çağrıları tercih edin Bağımsız servisleri Task.WhenAll ile paralel yapın.
Hata toleransı ekleyin Polly ile retry, circuit breaker, fallback.
Kritik/kritik olmayan veriyi ayırın Kritik olmayan servis başarısızsa kısmi yanıt dönün.
Caching kullanın Sık kullanılan verileri önbelleğe alın.
Batch çağrılar yapın N+1 probleminden kaçının.
Composer'ı ince tutun Sadece koordinasyon; iş mantığı servislerde.
Observability sağlayın Her servis çağrısını loglayın ve izleyin.

Sonuç

API Composition Pattern, mikroservis mimarisinde istemcinin tek istekte birden fazla servisten veri almasını sağlayan güçlü bir çözümdür. Paralel çağrılar, hata toleransı (Polly), caching ve batch çağrılar ile performansı optimize edebilir; graceful degradation ile kullanıcı deneyimini koruyabilirsiniz. CQRS ve GraphQL ile birlikte kullanıldığında daha da güçlü hale gelir. Unutmayın: Composer'ı ince tutun, iş mantığını servislerde bırakın ve her zaman hata senaryolarını planlayın.

Tüm yazılar Soru ya da yorumun mu var? Yaz