Geleneksel mimarilerin güvenli limanlarını terk edip mikroservislerin dağıtık dünyasına adım attığımızda, sistem mühendisliğinin en acımasız gerçeklerinden biriyle yüzleşiriz. Ağ sınırları üzerinden asenkron konuşan onlarca servisin olduğu bir ortamda ACID garantileri tamamen buharlaşır.

Tek bir veritabanı instance'ı içinde harikalar yaratan ilişkisel transaction yönetimi, bir işlem sipariş, stok ve ödeme servislerine yayıldığında çalışmaz. İş mantığı farklı sunuculara bölündüğünde, veritabanı kilitleri yerini ağ gecikmelerine ve veri tutarsızlıklarına bırakır.

Sistem mimarları olarak bu noktada kritik bir mimari karar vermek zorundayız. Dağıtık bir transaction'ı yönetmek için ya sistemin boğazını sıkan senkron kilit mekanizmalarına başvuracağız ya da Eventual Consistency prensiplerini kucaklayarak asenkron ve otonom bir akış tasarlayacağız.

Gerçek dünya ölçeğinde operasyon yapan kurumsal sistemlerde senkron kilitlerin yeri yoktur. Yüksek throughput ve düşük latency hedeflendiğinde, dağıtık işlemleri hatasız koordine etmenin tek rasyonel yolu Saga desenini uygulamaktır.

İki Aşamalı Onay Protokolünün İflası

Yıllarca dağıtık transaction yönetimi dendiğinde akla gelen ilk çözüm 2PC oldu. İki aşamalı onay protokolü, dağıtık sistemlerde mutlak tutarlılık sağlamayı vaat eder ve kağıt üzerinde kusursuz görünür.

Ancak bu yapı pratikte tam bir performans katilidir. 2PC protokolü, işleme katılan tüm node'ları prepare ve commit fazları boyunca kilitler. Bir node bile gecikse tüm sistem onu beklemek zorunda kalır.

Bir ağ kesintisi yaşandığında veya coordinator node çöktüğünde, tüm katılımcı servisler askıda kalır. Kaynaklar kilitlendiği için sistem yeni istekleri karşılayamaz hale gelir ve otonom mimari anında felç olur.

Bulut tabanlı, yatayda ölçeklenen modern mimarilerde Blocking I/O yaratan herhangi bir tasarım baştan ölü doğmuştur. Kilit mekanizmalarından tamamen arındırılmış, event-driven altyapılara yönelmemiz kurumsal entegrasyon için bir tercih değil teknik bir zorunluluktur.

Metrik Karşılaştırması 2PC Protokolü Saga Orkestrasyonu
Kilit Durumu (Locking) İşlem bitene kadar tüm kaynaklar kilitli Kilit yok, asenkron durum güncellemeleri
Ağ Hatası Toleransı Çok düşük (Coordinator bağımlılığı) Çok yüksek (Broker üzerinden kuyruklama)
Throughput Kapasitesi Düşük (Senkron bloklama nedeniyle) Yüksek (Event-driven akış)
İyileşme (Recovery) Manuel müdahale veya uzun timeoutlar Telafi edici olaylarla otonom rollback

Mimari Kavşak ve Tasarım Kararları

Saga desenini uygulamaya karar verdiğimizde, önümüzde iki ana yol ayrımı bulunur. Seçeceğimiz topoloji, sistemin gelecekteki bakım maliyetini ve operasyonel karmaşıklığını doğrudan belirler.

Koreografinin Cezbedici Basitliği ve Spagetti Kod Riski

Koreografi yaklaşımında merkezi bir yönetici yoktur. Servisler birbirlerinin fırlattığı eventleri dinleyerek kendi lokal işlemlerini yürütür. İki veya üç servisin dahil olduğu basit akışlarda bu model oldukça zarif ve hızlıdır.

Ancak kurumsal dünyada iş süreçleri sürekli evrilir. Sürece katılan servis sayısı dördü geçtiğinde, koreografi hızla dağıtık bir spagetti koda dönüşür.

Sistemin global state durumunu takip etmek imkansızlaşır. Hangi eventin hangi servisi tetiklediğini bulmak, logic akışını debug etmek ve cyclic dependency sorunlarını çözmek, geliştirici ekipleri için içinden çıkılmaz bir hal alır. Yeni bir adım eklemek, mevcut tüm servislerin event listener'larını değiştirmeyi gerektirebilir.

Orkestrasyonun Otoriter Yükselişi

Bu kontrolsüz kaosu ve dağıtık mantık karmaşasını engellemek için Saga Orkestrasyonu tasarımını devreye sokarız. Orkestrasyon, süreci yöneten akıllı bir State Machine olarak konumlanır.

Orkestratör, sürecin hangi aşamasında olduğumuzu, hangi servisin başarılı yanıt döndüğünü ve kimin hata verdiğini kesin olarak bilir. İlgili servislere yapmaları gereken işlemleri asenkron command mesajları olarak gönderir.

Servislerden gelen sonuç eventlerini dinleyerek kendi internal state bilgisini günceller. Orkestratör senkron bir bloklayıcı değildir. Mesajları kuyruğa bırakır, state bilgisini günceller ve mevcut thread'i derhal serbest bırakır.

Tasarım Kriteri Saga Koreografisi Saga Orkestrasyonu
Bileşen Bağımlılığı Servisler diğer domain eventlerini bilmeli Servisler sadece command mesajlarını dinler
Dağıtık İzlenebilirlik Karmaşık (Sadece trace loglarla izlenebilir) Basit (Orkestratör tüm state bilgisini tutar)
Döngüsel Bağımlılık Riski Yüksek (Event zincirleri sonsuz döngüye girebilir) Düşük (Merkezi karar mekanizması)
Geliştirme Maliyeti Başlangıçta düşük, ölçeklendikçe operasyonel kabus Başlangıçta yüksek, uzun vadede yönetimi kolay

Geriye Dönük Hata Telafisi ve Compensating Events

Saga mimarisinin kalbi, hata yönetimi stratejisinde atar. Dağıtık bir işlemde global bir rollback komutu yoktur. İşlemi veritabanı seviyesinde tek tuşla iptal edemeyiz.

Sürecin dördüncü aşamasında bir kural ihlali veya sistem hatası yaşandığında, önceki üç servis kendi lokal transactionlarını çoktan commit etmiştir. Müşterinin bakiyesi düşülmüş, kargo kaydı açılmış olabilir.

Saga bir veritabanı rollback işlemi değil, iş mantığı seviyesinde kurgulanan anlamsal bir geri alma operasyonudur.

Orkestratör, kritik bir hata algıladığında state durumunu failed olarak işaretler ve geriye dönük telafi fazını başlatır. Sırasıyla önceki adımları tersine çevirecek komutlar üretir.

Kargo servisine gönderilen CancelShipmentCommand ve ödeme servisine gönderilen RefundPaymentCommand mesajları, kuyruk üzerinden asenkron olarak iletilir. Bu adımlar veriyi fiziksel olarak silmez, mantıksal olarak önceki durumu yansıtacak yeni kayıtlar atar.

Buradaki en kritik mühendislik detayı, telafi edici işlemlerin kesinlikle başarısız olamayacağı varsayımı üzerine tasarlanmasıdır. Bir iade komutu, business logic hatası fırlatamaz. Sadece geçici ağ veya veritabanı kesintileri yaşanabilir.

Mesaj kuyruğu altyapısı, iade işlemi başarılı olana kadar bu mesajı hedef servise belirli backoff stratejileriyle tekrar tekrar iletmekle yükümlüdür.

Ağ Dalgalanmaları ve Idempotency Çıkmazı

Mesaj kuyruklarının yapısı gereği At-Least-Once delivery garantisi altında çalışırız. Exactly-Once delivery çoğu dağıtık sistem için bir efsaneden ibarettir. Ağdaki dalgalanmalar nedeniyle aynı telafi komutu veya event, bir servise birden fazla kez ulaşabilir.

Eğer ödemeyi iade et komutu iki kez işlenirse, müşteriye mükerrer para iadesi yapılır. Bu tür finansal ve operasyonel faciaları önlemek için consumer uç noktalarının etkisizlik prensibine göre tasarlanması şarttır.

Idempotency, modern dağıtık sistemlerde bir tercih değil, mutlak bir mimari zorunluluktur.

Gelen her mesajın payload'u içinde benzersiz bir Correlation ID barındırması gerekir. Hedef servis, bu kimliği iş mantığıyla aynı transaction bloğu içinde bir tracking table üzerine kaydeder.

Aynı kimliğe sahip bir mesaj tekrar geldiğinde, servis constraint ihlali sayesinde veya doğrudan tracking tablosundan okuma yaparak işlemin daha önce başarıyla tamamlandığını anlar. Bu durumda hata fırlatmaz, mesajı başarılı olarak işaretler ve doğrudan pas geçer.

Zehirli Haplar ve Hata İzolasyonu

Sistemler ne kadar fault-tolerant tasarlanırsa tasarlansın, telafi edilemeyen kalıcı hatalar daima oluşacaktır. Beklenmeyen bir veri tipi, eksik bir payload veya consumer servisindeki bir bug nedeniyle bir mesaj asla işlenemeyebilir.

Poison Pills ve DLQ Stratejisi

Bu tür durumlarda consumer servis sürekli exception fırlatır ve mesaj kuyruğun başına geri döner. Bu kısır döngüye Poison Pills adı verilir.

Poison pills, ilgili kuyruğu veya partition'ı tamamen bloke eder. Arkadan gelen sağlıklı ve geçerli mesajlar da işlenemez duruma gelir. Sistemin kilitlenmemesi için kusursuz bir Dead Letter Queue stratejisi uygulanmalıdır.

Belirli bir retry limitine ulaşan mesajlar, sistem tarafından otomatik olarak ana kuyruktan alınıp DLQ'ya taşınır. Bu sayede sağlıklı operasyonel akış kesintiye uğramaz.

DLQ'ya düşen mesajlar derhal monitoring araçları üzerinden kritik alarmlar üretmelidir. Manuel inceleme ve kod seviyesindeki hotfix işlemlerinin ardından, bu mesajların DLQ'dan ana kuyruğa tekrar beslenmesi kurumsal entegrasyonun veri kaybı yaşamasını engeller.

Dağıtık Anomaliler ve İzolasyon İhlalleri

Dağıtık Saga tasarımlarının mimari açıdan en zayıf karnı, izolasyon seviyesindeki eksikliktir. Geleneksel ACID özelliklerinden Isolation bu yapıda tam anlamıyla sağlanamaz.

Bir Saga işlemi dakikalar veya saatler sürebilir. Bu süreç boyunca ara durumlar diğer concurrent transactionlar tarafından anında görülebilir. Bu duruma Dirty Read anomalisi diyoruz.

Örneğin bir kullanıcının bakiyesinden para düşülmüş ancak Saga süreci henüz tamamlanmamış olabilir. Başka bir paralel süreç bu düşük bakiyeyi okuyup buna göre karar verirse ve orijinal Saga sonradan geriye doğru telafi edilirse, veritabanı tutarsız ve kurgusal bir duruma sürüklenir.

Semantic Lock ile Manuel İzolasyon

Bu anomalileri engellemek için iş mantığı seviyesinde Semantic Lock yöntemini kullanırız. Kayıtlar doğrudan son halleriyle güncellenmek yerine PENDING veya LOCKED gibi ara durumlara çekilir.

Diğer mikroservisler bir kaydın PENDING durumunda olduğunu gördüğünde, o kayıt üzerinde işlem yapmayı reddedebilir veya Saga'nın tamamlanmasını bekleyecek şekilde işlemi kuyruğa geri atabilir.

Bu, veritabanı motorunun değil, doğrudan uygulamanın iş mantığı katmanında yürütülen manuel bir izolasyon yöntemidir ve dağıtık transactionların olmazsa olmazıdır.

Orkestratörün Kendi Çöküşü ve Dual Write Problemi

Bir orkestratör tasarlarken kodun mükemmel çalışacağını ve sunucunun asla kapanmayacağını varsaymak büyük bir mühendislik hatasıdır. Yüksek yük altında orkestratörün kendisi de crash olabilir.

Bir event orkestratöre ulaştığında, orkestratör state güncellemesini veritabanına yazar ve hemen ardından yeni command mesajlarını broker'a fırlatır. Bu duruma Dual Write problemi denir.

Eğer veritabanı güncellendikten hemen sonra, komutları kuyruğa fırlatamadan orkestratör donanımsal bir hata nedeniyle çökerse, sistem araf durumunda kalır. Veritabanındaki state değişmiş ama ilgili aksiyonlar alınmamıştır.

Outbox Pattern ile Güvenli İletişim

Bu yıkıcı riski ortadan kaldırmak için state geçişleri ve event fırlatma işlemleri Outbox Pattern üzerinden tek bir lokal transaction ile yönetilmelidir. Orkestratör, hem state güncellemesini hem de fırlatılacak mesajları aynı veritabanı transaction'ı içinde lokal tablolara yazar.

Message broker ile iletişim, orkestratörün doğrudan sorumluluğundan çıkarılır. Ayrı bir background worker veya Write-Ahead Log üzerinden çalışan bir CDC aracı, Outbox tablosunu okuyarak mesajları kuyruğa güvenle iletir.

Orkestratör çöksün veya ağ kopsun, veritabanı transaction'ı commit edildiği sürece outbox tablosundaki mesajlar er ya da geç broker'a ulaşacaktır. Bu mimari, Dual Write anomalisini tamamen ortadan kaldırır.

Üretim Ortamı Gerçekleri ve Darboğaz Testleri

Mimari tasarımların doğruluğu beyaz tahtada çizilen oklarla değil, üretim ortamı simülasyonlarındaki metriklerle kanıtlanır. Tasarlanan Saga orkestratörünün yük altında nasıl davrandığını görmek için agresif performans testleri yapılması elzemdir.

Saniyede binlerce isteğin geldiği bir ortamda, asenkron yapının mesaj kuyruğunda yaratacağı consumer lag ve veritabanı yazma performansları ölçülmelidir. Outbox Pattern ile desteklenmiş bir Saga orkestratörünün örnek performans metriklerini incelemek, sistemin sınırlarını anlamamızı sağlar.

Gelen İstek Yükü Saga Başarı Oranı Başarılı İşlem Süresi (P95) Telafi İşlemi Süresi (P95) DLQ Düşme Oranı
1.000 Req/Sec 99.9% 120ms 340ms 0.01%
5.000 Req/Sec 99.5% 180ms 410ms 0.05%
10.000 Req/Sec 98.2% 350ms 850ms 0.20%
25.000 Req/Sec 92.4% 890ms 2100ms 1.50%

Bu tablo, orkestratörün asenkron yapısı sayesinde yüksek istek yüklerini sistemi çökertmeden karşılayabildiğini net bir şekilde gösterir. 2PC kullanan senkron bir sistemin bu yüklerin onda birinde connection pool'ları tüketerek kilitleneceği mimari bir gerçektir.

Ancak yük arttıkça consumer lag değerlerinin yükselmesi, başarılı ve telafi edilmiş işlemlerin latency sürelerini kaçınılmaz olarak uzatmaktadır. Özellikle telafi süreçleri birden fazla asenkron atlama gerektirdiği için gecikmeler daha belirgindir.

25.000 Req/Sec seviyelerinde DLQ düşme oranındaki dramatik artış, veritabanı disk I/O kapasitelerinin veya broker limitlerinin sınıra ulaştığına işaret eder. Bu noktada orkestratör instance'larının ve mesaj kuyruğu partition stratejilerinin yatayda agresif bir şekilde ölçeklenmesi gerekir.

Deterministik Olmayan Sistemleri Yönetmek

Dağıtık işlemleri hatasız yönetmek, sadece temiz kod yazmaktan ibaret değildir. Bu tamamen bir sistem dizaynı ve etki alanı analizi problemidir. Bileşenlerin her an çökebileceğini kabul ederek tasarıma başlamak, modern mimarinin temel felsefesidir.

Senkron kilitlerin getirdiği hantal ve bloklayıcı yapılardan kurtulup Saga orkestrasyonunu kucakladığımızda, sistemin elastikiyeti ve throughput kapasitesi maksimuma çıkar. Hata toleransı artık sonradan eklenmiş bir try-catch bloğu değil, mimarinin çekirdek bir refleksidir.

İş kurallarının parçalı olarak işletildiği, hataların telafi edici olaylarla anında geriye sarıldığı ve işlenemeyen mesajların DLQ mekanizmalarıyla güvenle park edildiği bu yapılar, otonom kurumsal altyapıların yegane standardıdır.

Kıdemli sistem mühendisleri olarak temel görevimiz, tüm ağ çağrılarının başarılı olduğu deterministik o nadir anları tasarlamak değildir. Asıl görevimiz; ağların koptuğu, veritabanlarının yanıt vermediği ve event'lerin kaybolduğu durumlarda bile veri tutarlılığını koruyabilen sarsılmaz mimariler inşa etmektir. Dağıtık mikroservis dünyasında ayakta kalmanın tek yolu budur.