Saga Pattern ile Dağıtık Transaction'lar: ACID Olmadan Consistency Sağlamak
Microservices mimarisinde AWS Step Functions ve EventBridge kullanarak Saga pattern implementasyonu: idempotency, compensation logic ve production-ready pattern'ler.
Özet
Saga pattern, microservices mimarisinin en zorlu problemlerinden birini çözüyor: servisler arasında geleneksel ACID transaction'lar olmadan data consistency sağlamak. Bu yazıda, AWS Step Functions orchestration ve EventBridge choreography kullanarak saga implementasyonu, etkili compensation logic tasarımı, idempotency garantisi ve dağıtık sistemlerdeki isolation sorunlarını ele alıyorum. Orchestration ile choreography arasında ne zaman hangisini seçeceğini, concurrent saga conflict'leri önlemek için semantic locking'i nasıl uygulayacağını ve production ortamları için kritik observability pattern'lerini öğreneceksin.
Dağıtık Transaction Problemi
Microservices geliştirirken, hızlıca temel bir zorlukla karşılaşırsın: bağımsız servisler arasında multi-step transaction'ları koordine etmek. Geleneksel ACID transaction'lar servis sınırları arasında çalışmaz ve two-phase commit (2PC) sıkı coupling ve single point of failure yaratır.
Tipik bir e-commerce sipariş akışını düşün: sipariş oluşturma, stok rezervasyonu, ödeme işleme ve kargo onayı. Her adım farklı bir microservice ve kendi database'ine sahip. Stok rezerve edildikten sonra ödeme işleme başarısız olursa, stok rezervasyonunu geri almanın güvenilir bir yoluna ihtiyacın var. Doğru pattern'ler olmadan, servisler inconsistent hale gelir; siparişler oluşturulur, ödemeler başarısız olur, stok restore edilmez. Production'da bu tür partial failure'lar nadir değil—ağ timeout'ları, rate limit'ler veya geçici servis kesintileri compensation logic'i zorunlu kılar. Orchestration sıralı flow'lar için; choreography gevşek bağlı event stream'ler için—seçim complexity ve ekip yapısına bağlıdır. Step Functions orchestration karmaşık saga'lar için daha yönetilebilir; EventBridge choreography loose coupling sağlar.
Saga pattern bu probleme local transaction'lar ve compensating transaction'lar aracılığıyla yapılandırılmış bir yaklaşım sunuyor. Distributed transaction yerine, her adımın daha sonraki bir adım başarısız olursa compensating transaction ile geri alınabildiği bir dizi local transaction çalıştırıyorsun. Orchestration (merkezi koordinatör) veya choreography (event-driven) ile implement edilebilir; karmaşık flow'lar için Step Functions orchestration genellikle daha yönetilebilir olur. Önemli olan: her compensating transaction'ın kendi servisinde tam bir "undo" sağlaması ve idempotent olmasıdır – aynı compensation'ın iki kez çalışması ek yan etki yaratmamalıdır.
Saga Pattern Temelleri
Bir saga, şu şekilde işleyen bir dizi local transaction'dır:
- Her transaction tek bir servis içindeki data'yı günceller
- Her transaction bir sonraki transaction'ı tetiklemek için event veya message publish eder
- Bir transaction başarısız olursa, saga tamamlanan adımları geri almak için compensating transaction'ları çalıştırır
- Sistem anlık ACID consistency yerine eventual consistency sağlar
Saga'ları çalıştıran temel özellikler:
- Eventual Consistency: Sistem hemen değil, zaman içinde consistent hale gelir
- Local Transaction'lar: Her servis kendi database'ini local ACID garantileriyle yönetir
- Compensating Transaction'lar: Her forward step için explicit rollback logic
- Idempotency: Tüm saga step'leri retry-safe olmalı
- Observability: Distributed flow'ları debug etmek için kritik—saga state'ini izleyemezsen, başarısız adımları ve compensation gereksinimlerini tespit etmek imkânsız hale gelir. Correlation ID'ler ve structured logging her saga step'inde zorunludur.
Saga pattern'i ne zaman kullanmalısın:
- Birden fazla database'i olan microservices mimarisi
- Birden fazla servisi kapsayan business process'ler
- Performance veya coupling endişeleri nedeniyle distributed transaction'lar kullanılamıyor
- Geçici inconsistency kabul edilebilir
- Tipik olarak maksimum 3-5 step (bunun ötesinde complexity hızla artar)
Orchestration vs Choreography
Saga'ları koordine etmenin iki ana yaklaşımı var: orchestration ve choreography. Hangisini ne zaman kullanacağını anlamak başarılı implementasyon için kritik.
Choreography: Event-Driven Koordinasyon
Choreography'de servisler merkezi bir coordinator olmadan domain event'ler aracılığıyla koordine olur. Her servis bir event aldığında ne yapacağını bilir.
Avantajları:
- Servisler arasında loose coupling
- Single point of failure yok
- Independent servisler için iyi scale eder
- Event-driven architecture için doğal fit
Dezavantajları:
- Control flow tek bir yerde görünmüyor
- Tüm saga flow'unu anlamak zor
- Debugging complexity (distributed logic)
- Saga state'i track etmek daha zor
- Cyclic dependency riski
En uygun durumlar:
- Maksimum 3-4 servis
- Independent, autonomous servisler
- Mevcut event-driven architecture
- Basit linear flow'lar
Orchestration: Merkezi Koordinasyon
Orchestration'da merkezi bir coordinator (tipik olarak AWS Step Functions) saga flow'unu yönetir, her servise ne yapacağını söyler.
Avantajları:
- Net control flow visualization
- Daha kolay debugging ve monitoring
- Centralized error handling
- Built-in state management
- Complex flow'lar için daha iyi
Dezavantajları:
- Orchestrator coordination point
- Servisler orchestrator'a coupled
- Orchestrator tüm servisleri bilmeli
En uygun durumlar:
- Kompleks multi-step workflow'lar
- Saga state'e visibility gerekli
- Human approval step'leri var
- 4'ten fazla servis involved
- Strict ordering gereksinimleri
Karar Framework'ü
Yaklaşımını seçerken bu karar logic'ini kullan:
AWS Step Functions ile Orchestration Implementasyonu
AWS CDK kullanarak production-ready bir e-commerce sipariş saga implementasyonunu göstereyim.
Infrastructure Setup
Bu infrastructure, doğru compensation chain'leriyle complete bir order processing saga setup'ı yapıyor. Her step'in transient error'lar için retry configuration'ı olduğuna ve compensation flow'larının reverse order'da build edildiğine dikkat et; bu tamamlanmış step'leri doğru şekilde geri almak için kritik.
Idempotent Operation'ları Implement Etmek
Saga'larda idempotency tartışmasız gerekli. Step'ler retry'lar, failure'lar veya network sorunları nedeniyle birden fazla kez execute olabilir. Düzgün idempotent operation'ları nasıl implement edeceğini göstereyim:
Başlangıçtaki idempotency check, bu function aynı transactionId ile birden fazla kez execute olursa side effect olmadan aynı sonucu döndürmesini sağlıyor. Conditional expression atomic bir "semantic lock" sağlıyor; sadece yeterli quantity varsa stok rezerve ediyor.
Compensation: Stok Serbest Bırakma
Compensation'ın da idempotent olduğuna dikkat et. Reservation yoksa success dönüyoruz; istenen end state zaten sağlanmış.
Idempotency ile Ödeme İşleme
Ödeme işleme de aynı prensipleri takip etmeli: idempotency key (transactionId), conditional write'lar ve retry-safe logic. Payment provider'ın idempotency key'lerini kullan; aynı key ile tekrarlanan çağrılar duplicate charge oluşturmamalı.
EventBridge ile Choreography Implementasyonu
Daha basit flow'lar için choreography daha iyi decoupling sağlayabilir. Event-driven saga koordinasyonunu nasıl implement edeceğini göstereyim:
Choreography'de her servis ilgili event'leri dinlemek ve yeni event'ler publish etmekten sorumlu. Compensation da aynı event mekanizması üzerinden gerçekleşiyor; bir servis failure event'i publish ettiğinde, diğer servisler compensating transaction'larını execute ederek react ediyor.
Semantic Locking ile Isolation
Saga'lar geleneksel transaction isolation'dan yoksun, bu da concurrent saga conflict'lerine yol açabilir. Semantic locking application-level isolation sağlıyor:
Bu semantic lock, iki saga'nın aynı siparişi concurrent olarak modify etmesini önlüyor. Lock, saga crash olduğunda lock'u release edememe durumlarını handle etmek için expiration time içeriyor.
Maliyet Analizi ve Trade-off'lar
Maliyet etkilerini anlamak doğru yaklaşımı seçmene yardımcı oluyor.
Step Functions Orchestration Maliyetleri
100,000 sipariş/ay için 8-step saga:
- Total state transition: 800,000
- Maliyet: (800,000 / 1,000) × 20/ay**
- Başarısız saga'lar (4-step compensation ile %5): ~20,000 transition = +$0.50/ay
- Toplam: ~$20.50/ay
EventBridge Choreography Maliyetleri
100,000 sipariş/ay için sipariş başına 4 event:
- Total event: 400,000
- Maliyet: (400,000 / 1,000,000) × 0.40/ay**
- Compensation ile başarısız siparişler: +$0.03/ay
- Toplam: ~$0.43/ay
Gerçek Trade-off
Choreography önemli ölçüde daha ucuz ama daha yüksek development ve debugging complexity'siyle geliyor. Orchestration daha pahalı ama daha iyi visibility ve daha kolay troubleshooting sağlıyor. Çoğu production sistemde, orchestration'ın improved observability'si ek maliyete değiyor.
Yaygın Hatalar ve Çözümler
Hata 1: Non-Idempotent Operation'lar
Problem: Retry'da ödeme birden fazla kez alınıyor.
Çözüm: Her zaman idempotency check'leri implement et ve provider idempotency key'leri kullan.
Hata 2: Eksik Compensation Chain'leri
Problem: Sadece son step compensate ediliyor, daha önceki step'ler inconsistent state'te kalıyor.
Çözüm: Tüm compensation'ları reverse order'da chain'le. Her catch block önceki tüm step'leri compensate etmeli.
Hata 3: Compensation Failure'larını Ignore Etmek
Problem: Compensation başarısız oluyor, saga askıda kalıyor.
Çözüm: Compensation'lar için aggressive retry (10+ attempt) ve manual intervention için dead-letter queue.
Hata 4: Timeout Çok Kısa
Problem: Timeout compensation'ı tetikliyor ama operation aslında başarılı olmuştu.
Çözüm: Buffer ile gerçekçi timeout'lar belirle. Compensate etmeden önce gerçek state'i doğrula.
Hata 5: Choreography'de Saga State Takibi Yok
Problem: Hangi siparişlerin compensation'da olduğu belirlenemiyor.
Çözüm: Observability için choreography'de bile saga state'ini persist et.
Önemli Çıkarımlar
- Kompleks flow'lar için orchestration seç (>4 servis), basit linear flow'lar için choreography
- Idempotency kritik; her saga step doğru key'lerle idempotent olmalı
- Reverse order'da compensate et; compensation'ları idempotent ve retryable yap
- Semantic locking kullan concurrent saga conflict'leri önlemek için
- Gerçekçi timeout'lar belirle ve compensate etmeden önce state'i verify et
- İlk günden observability implement et; structured logging, metrics, tracing
- Saga'ları basit tut (3-5 step); kompleks workflow'lar için birden fazla saga chain'le
- Saga state'i persist et choreography'de bile debugging için
- Compensation'ları aggressively retry et manual intervention gerektiren failure'lar için DLQ ile
- Maliyet vs complexity'yi düşün; orchestration daha iyi visibility sağlar ama daha pahalı
Saga pattern, microservices'te distributed transaction'lar için robust bir çözüm sağlıyor. Orchestration ile choreography arasındaki trade-off'ları anlayarak, doğru idempotency ve compensation implement ederek ve güçlü observability kurarak, servis sınırları arasında consistency'yi koruyan güvenilir dağıtık sistemler geliştirebilirsin.
Helper Functions
Örneklerde referans verilen basitleştirilmiş helper fonksiyonları (saveOrder, getOrder, reserveInventoryForOrder, releaseInventory, processPayment, updateOrderStatus) – tam implementasyon için EN versiyonuna bakın.