Saga Pattern Nedir? Mikroservisler Arasında İşlem Yönetimi

Modern yazılım mimarilerinde, özellikle mikroservis mimarisinin popülaritesinin artmasıyla birlikte, sistemler birbirinden bağımsız çalışan servislerin birlikte iş birliği yaptığı dağıtık yapılara evrildi. Mikroservisler, belirli bir işlevi yerine getiren bağımsız birimlerdir ve her bir servis, kendi veri tabanı ve iş mantığıyla ayrı ayrı çalışabilir. Ancak bu bağımsız yapılar bir işlemin parçası olduğunda, tüm işlem adımlarının tutarlılığı ve başarısızlık durumunda geri alınabilirlik (rollback) önemli bir sorun haline gelir.

Bu noktada, Saga Pattern devreye girer. Saga Pattern, dağıtık sistemlerdeki uzun süreli işlemleri yönetmek ve adım adım başarısızlık durumlarında sistemi geri almak için kullanılan bir tasarım desenidir.

Saga Pattern Nedir?

Saga Pattern, bir işlemi küçük adımlara bölen ve bu adımları bağımsız mikroservisler aracılığıyla işleten bir desendir. Bu desenin temel amacı, bir mikroservisin başarısız olması durumunda tüm işlemi geri almak yerine, sadece başarısız olan işlemin etkilerini geri almak ve sistemi tutarlı bir duruma döndürmektir.

Her adım başarılı olursa sonraki adım başlatılır. Eğer bir adımda hata oluşursa, önceden gerçekleştirilen adımlar geri alınır. Bu geri alma işlemi, o adım için tanımlanmış tazmin edici işlemler (compensating actions) ile yapılır.

Saga Pattern İki Ana Yaklaşıma Ayrılır:

  1. Koordinatör Tabanlı Saga (Orchestration-based Saga): Bir merkezi koordinatör, işlemi adım adım yönlendirir ve hatalar oluştuğunda geri alma işlemlerini tetikler.
  2. Koreografi Tabanlı Saga (Choreography-based Saga): Merkezi bir koordinatör olmadan, her servis birbirine olaylar (events) aracılığıyla haberleşir ve işlemi bağımsız olarak yürütür.

Saga Pattern’in Temel Bileşenleri

  1. İşlem (Transaction): Her mikroservis bir işlemi gerçekleştirir. Bu işlem bir adımı temsil eder.
  2. Tazmin Edici İşlem (Compensating Transaction): Eğer bir işlem başarısız olursa, önceki adımlar geri alınmalıdır. Bu geri alma işlemi tazmin edici işlemlerle yapılır.
  3. Koordinatör (Coordinator): Orchestration modelinde merkezi bir koordinatör, tüm adımların sırasını yönetir. Her adım başarılı olursa, bir sonraki adım çağrılır. Başarısız olursa, geri alma işlemleri tetiklenir.

Saga Pattern Türleri

1. Koordinatör Tabanlı Saga (Orchestration-based Saga)

Bu yaklaşımda merkezi bir koordinatör tüm adımları yönetir. İşlemler sırayla gerçekleştirilir ve her adım başarılı olursa, koordinatör bir sonraki adımı tetikler. Bir hata oluşursa, geri alma işlemleri (rollback) başlatılır.

Avantajları:

  • Merkezi koordinatör sayesinde süreç kolayca takip edilebilir.
  • İşlemler ve tazmin edici işlemler merkezi bir mantıkla kontrol edilir.

Dezavantajları:

  • Merkezi koordinatör bir bağımlılık oluşturur. Eğer bu koordinatör devre dışı kalırsa tüm sistem durabilir.
  • Merkezi koordinatörün karmaşıklığı arttıkça yönetim zorlaşabilir.

Örnek Senaryo:

Bir e-ticaret sisteminde, sipariş oluşturulurken stok, ödeme ve kargo işlemleri sırasıyla gerçekleştirilir. Eğer ödeme sırasında bir hata oluşursa, önceden ayrılan stok tekrar serbest bırakılmalıdır.

Adımlar:

  1. Sipariş oluşturulur.
  2. Stok kontrolü yapılır.
  3. Ödeme işlemi gerçekleştirilir.
  4. Kargo işlemi başlatılır.

Eğer bir adım başarısız olursa, önceki adımlar geri alınmalıdır. Örneğin, ödeme başarısız olursa stok iadesi gerçekleştirilir.

2. Koreografi Tabanlı Saga (Choreography-based Saga)

Bu yaklaşımda merkezi bir koordinatör yoktur. Her mikroservis bir önceki işlemin sonucuna abone olur ve kendi işlemini tetikler. Servisler birbirine olaylar aracılığıyla haberleşir.

Avantajları:

  • Merkezi bir koordinatör olmadığı için sistem daha az bağımlıdır.
  • Mikroservisler arasında daha gevşek bağlılık (loose coupling) vardır.

Dezavantajları:

  • Olay tabanlı sistemlerde hata ayıklamak daha zor olabilir.
  • Her servis kendi işlem mantığını yönetir, bu da karmaşıklığı artırabilir.

Örnek Senaryo:

Aynı e-ticaret sisteminde, her mikroservis bir önceki işlemin sonucuna göre tetiklenir. Stok kontrol servisi başarılı olursa, ödeme servisi tetiklenir; ödeme başarılı olursa kargo servisi tetiklenir.

C# ile Saga Pattern Örneği (Koordinatör Tabanlı)

Aşağıda C# dilinde bir Saga Pattern örneği sunulmuştur. Örnek senaryoda bir e-ticaret siparişi işlemi gerçekleştirilir. Bu süreçte Stok Servisi, Ödeme Servisi, ve Kargo Servisi adımlarını içerir. Eğer herhangi bir adım başarısız olursa, önceki adımlar geri alınır.

C# Kod Örneği:

// Saga adımlarını temsil eden sınıflar:
public interface ISagaStep
{
    void Execute();
    void Rollback();
}

// Stok kontrolü adımı
public class StockService : ISagaStep
{
    public void Execute()
    {
        Console.WriteLine("Stock reserved.");
    }

    public void Rollback()
    {
        Console.WriteLine("Stock released.");
    }
}

// Ödeme servisi adımı
public class PaymentService : ISagaStep
{
    public void Execute()
    {
        Console.WriteLine("Payment processed.");
    }

    public void Rollback()
    {
        Console.WriteLine("Payment refunded.");
    }
}

// Kargo servisi adımı
public class ShippingService : ISagaStep
{
    public void Execute()
    {
        Console.WriteLine("Shipping initiated.");
    }

    public void Rollback()
    {
        Console.WriteLine("Shipping cancelled.");
    }
}

// Saga koordinatörü
public class OrderSaga
{
    private List<ISagaStep> _steps = new List<ISagaStep>();
    private int _currentStep = -1;

    public void AddStep(ISagaStep step)
    {
        _steps.Add(step);
    }

    public void Execute()
    {
        try
        {
            foreach (var step in _steps)
            {
                _currentStep++;
                step.Execute();
            }
        }
        catch (Exception)
        {
            Console.WriteLine("Error occurred, rolling back...");
            Rollback();
        }
    }

    private void Rollback()
    {
        for (int i = _currentStep; i >= 0; i--)
        {
            _steps[i].Rollback();
        }
    }
}

// Kullanım
public class Program
{
    public static void Main(string[] args)
    {
        var saga = new OrderSaga();
        saga.AddStep(new StockService());
        saga.AddStep(new PaymentService());
        saga.AddStep(new ShippingService());

        saga.Execute();
    }
}

Açıklama:

  • StockService, PaymentService, ve ShippingService sınıfları, Saga Pattern içindeki adımları temsil eder.
  • OrderSaga sınıfı, adımları koordine eder ve geri alma işlemlerini yönetir.
  • Eğer bir adım başarısız olursa, önceki adımların geri alınması sağlanır.

Saga Pattern Kullanım Alanları

  • E-ticaret Sistemleri: Sipariş işlemleri, stok kontrolü, ödeme, kargo gibi birbirine bağımlı işlemlerin yönetimi için kullanılır.
  • Uçak Rezervasyon Sistemleri: Uçuş rezervasyonu, ödeme ve koltuk ayrımı gibi işlemler bir Saga ile yönetilebilir.
  • Banka ve Finansal Sistemler: Para transferi, kredi kartı işlemleri ve borç tahsili gibi uzun süreli işlemler için uygundur.

Saga Pattern’in Avantajları

  1. Tutarlılık Sağlar: Dağıtık işlemlerin tutarlı bir şekilde tamamlanmasını sağlar ve hatalarda geri alma işlemlerini kolaylaştırır.
  2. Dağıtık Sistemler İçin İdealdir: Mikroservisler arasında işlem yönetimi sağlar.
  3. Modülerlik ve Esneklik: İşlem adımlarını ayrı ayrı

yöneterek esnek ve modüler bir yapı sunar.

Saga Pattern’in Dezavantajları

  1. Karmaşıklık: Özellikle büyük sistemlerde Saga Pattern’in yönetimi zor olabilir. Hem işlemleri hem de geri alma işlemlerini yönetmek ekstra kodlama ve mantık gerektirir.
  2. Zaman Senkronizasyonu: Mikroservisler arasında işlemler uzun süre alabilir. Zaman uyumsuzluğu sorunlara yol açabilir.

Sonuç

Saga Pattern, özellikle mikroservis mimarileri için işlem yönetimi açısından kritik bir desen olarak öne çıkar. Dağıtık sistemlerde adım adım işlemler yürütülürken, her adımın bağımsız olarak yönetilmesi ve hatalar durumunda geri alınabilirlik sunması bu deseni cazip kılar. Saga Pattern, e-ticaret, bankacılık ve rezervasyon sistemleri gibi uzun süreli ve birbirine bağımlı işlemlerin olduğu senaryolarda güvenli bir çözüm sağlar.

Saga Pattern’i doğru uygulamak, karmaşık sistemlerde bile tutarlılık ve güvenlik sağlayarak kullanıcı deneyimini iyileştirebilir. Bu nedenle, dağıtık sistemlerle çalışan her yazılımcının bu deseni iyi anlaması ve projelerinde kullanması önemlidir.