Oyun Kitabı
Ödeme Sistemleri Neden Dağıtık Sistemlerdir? (Odeme Sistemleri Neden Dagitik Sistemlerdir)
Bir ödeme tek bir servisin işi değildir: sepet, stok, provider gateway ve finans aynı gerçek üzerinde anlaşmak zorundadır. Senkron zincir neden kırılır?
Dağıtık Ödeme Motoru (Distributed Payment Engine)
Bolum 1 / 22
Capture ile complete arasındaki boşluğu kapatan dağıtık ödeme mimarisi serisi.
Ödeme bir buton değildir, bir koordinasyondur
Bir e-ticaret platformunda “ödeme al” dediğinizde aslında beş farklı sistemin aynı gerçek üzerinde anlaşmasını istersiniz: sepet dondurulmuş mu, stok var mı, provider gateway parayı aldı mı, sipariş onaylandı mı, finans kaydı doğru mu. Bunların hepsi tek bir process içinde, tek bir transaction'da yaşamaz.
Sepet Servisi Stok Servisi Checkout Orchestrator Provider Gateway Finans/Ledger
| | | | |
+---------------+------------------+--------------------+----------------+
aynı sipariş, beş farklı gerçek
Bu yazı, ödeme akışını neden “bir servisin fonksiyonu” gibi değil, dağıtık bir sistem problemi gibi tasarlamanız gerektiğini anlatıyor.
Kavramlar ilk geçtiği yerde
📦 Checkout Orchestrator
Sipariş akışının adımlarını (sepet, ödeme, stok, onay) koordine eden servis; para veya stok tutmaz, kararları sıralar.
📦 Provider Gateway
Gerçek ödeme sağlayıcısını (PSP) uygulama iç modeline çeviren soyutlama katmanı.
📦 PSP (Payment Service Provider)
Kartı veznede tutan, parayı fiilen çeken dış sistem; sizin transaction sınırınızın dışındadır.
📦 Dağıtık Transaction
Birden fazla bağımsız sistemin, tek bir “hepsi ya da hiçbiri” garantisi altında değişmesi gereken işlem.
📦 Eventual Consistency
Sistemlerin şu an değil, kısa bir süre içinde aynı gerçeğe yakınsayacağını kabul eden tutarlılık modeli.
Bu beş kavramı ayırt edemeyen bir ekip, PSP'yi kendi veritabanı gibi davranmaya zorlar. PSP asla sizin transaction'ınıza katılmaz; o yalnızca kendi gerçeğini, kendi zaman çizelgesinde bildirir.
Tek istek, beş imza gerektirir
Bir müşteri “Öde” butonuna bastığında, arka planda sırayla şu kararlar verilir: sepet fiyatı donduruldu mu, stok rezerve edildi mi, provider gateway'e ödeme isteği gitti mi, PSP parayı çekti mi, sipariş satırları finalize edildi mi, finans kaydı açıldı mı. Bunların her biri farklı bir servisin sorumluluğundadır ve farklı bir veritabanında yaşar.
Problem burada başlar: Bu altı adımı tek bir HTTP isteği zinciri içinde senkron olarak çağırırsanız, sistem bir tek noktadan diğerine bağımlı, uzun ve kırılgan bir zincir haline gelir.
Client → Checkout Orchestrator → Sepet Servisi → Stok Servisi → Provider Gateway → PSP
Senkron zincir nerede kırılır
Bu zincirde herhangi bir adım timeout verdiğinde iki soruyla baş başa kalırsınız: İstek karşı tarafa ulaştı mı, ulaştıysa işlendi mi? PSP'den dönen bir timeout, “para çekilmedi” anlamına gelmez; “cevabı alamadım” anlamına gelir. Aynı isteği tekrar göndermek, müşteriyi iki kez veznede bırakabilir.
Checkout Orchestrator --(timeout)--> Provider Gateway --(???)--> PSP
para çekildi mi, çekilmedi mi?
Bu belirsizlik, senkron zincirin doğal sonucudur: Ağ, tanım olarak güvenilmezdir; zinciri ne kadar uzatırsanız, belirsizlik o kadar birikir.
“Hepsi ya da hiçbiri” neden burada çalışmaz
Klasik dağıtık transaction çözümleri (two-phase commit gibi) tüm katılımcıların aynı koordinatöre, aynı kilitleme protokolüne ve aynı ağ güvenilirliğine sahip olmasını bekler. PSP bu dünyanın parçası değildir: kendi kilidini açmaz, sizin commit/rollback çağrınızı dinlemez, kendi zaman çizelgesinde (webhook, gecikmeli bildirim) sizi bilgilendirir.
Bu yüzden “ödeme + stok + sipariş” üçlüsünü tek bir transaction'a sığdırmaya çalışmak, çözülemeyen bir problemi çözülmüş gibi göstermektir. Gerçekte yaptığınız şey, hatayı gizlemektir; ortadan kaldırmamışsınızdır.
Olay tabanlı çözüm: iki farklı gerçek, iki farklı zaman çizelgesi
Çalışan model, senkron zinciri kısaltıp geri kalanını olaylara devretmektir. Provider gateway'e istek gönderirsiniz, PSP'nin cevabını (senkron ya da webhook ile) bir olay olarak kaydedersiniz, ve sipariş/stok/finans tarafındaki her adım bu olaya tepki veren, kendi başına idempotent birer tüketicidir.
Provider Gateway → PaymentCaptured (event) → Outbox
↓
Stok Servisi Finans Servisi Checkout Orchestrator
(bağımsız, kendi hızında, kendi retry'ıyla tüketir)
Bu modelde “ödeme başarılı” ve “sipariş tamamlandı” artık aynı anda gerçekleşen tek bir olay değil, birbirini takip eden, aralarında ölçülebilir bir gecikme olabilen iki farklı gerçektir. Bu ayrımı kabul etmeyen sistemler, bu serinin ikinci bölümünde göreceğimiz durum makinesi hatalarına doğru ilerler.
Bu bölümde en çok karışan eşleştirmeler
❌ Ödeme akışı = tek bir servisin fonksiyonu
✓ Ödeme akışı = birden fazla bağımsız servisin katıldığı bir koordinasyon
❌ PSP = bizim veritabanımızdaki bir tablo gibi davranır
✓ PSP = kendi zaman çizelgesi olan, dışarıdan gözlemlenen bir sistem
❌ Timeout = işlem başarısız oldu
✓ Timeout = işlemin sonucu bilinmiyor; retry idempotent olmadan güvenli değildir
❌ Dağıtık transaction ile bu problem “çözülebilir”
✓ Dağıtık transaction, PSP gibi harici sınırlarda pratikte uygulanamaz
Bu dört yanlış eşleştirme, çoğu “ödeme neden bazen çift çekiliyor” incident'inin köküdür.
Kendi sisteminizi denetleme listesi
- Ödeme akışınızda kaç farklı servis, kaç farklı veritabanına yazıyor? Bu sayıyı yazın.
- Provider gateway'e giden çağrı timeout verdiğinde, kodunuz otomatik retry yapıyor mu? Bu retry idempotency key taşıyor mu?
- “Ödeme başarılı” bilgisi ile “sipariş tamamlandı” bilgisi aynı satırda mı, farklı tablolarda mı tutuluyor?
- PSP'den gelen webhook gecikirse veya hiç gelmezse, sisteminiz kaç saat sonra fark ediyor?
- Senkron zincirinizde en uzun adım hangisi ve o adım düşerse geri kalan adımlar ne yapıyor?
Bu beş soruya net cevabınız yoksa, ödeme akışınız muhtemelen “tek transaction” yanılsamasıyla tasarlanmıştır.
Bu bölümden aklında kalması gerekenler
- Bir ödeme, tek bir servisin işlemi değildir; sepet, stok, provider gateway ve finansın aynı gerçek üzerinde anlaştığı bir koordinasyondur.
- Senkron HTTP zinciri, her ek adımda belirsizliği çarparak biriktirir; timeout bir sonuç değil, bir bilinmezliktir.
- PSP sizin transaction sınırınızın parçası değildir; onunla senkron kilit değil, olay sözleşmesiyle konuşursunuz.
- Eventual consistency bir eksiklik değil, dış dünyanın (özellikle PSP'nin) gerçek davranışının kabul edilmesidir.
Ödeme sistemini “anlık ve tek parça” gibi tasarlarsanız, üretimde “gecikmeli ve çok parçalı” gerçekle çarpışırsınız.
SSS
Sık sorulan sorular
Checkout Orchestrator nedir?
Sipariş akışının adımlarını (sepet, ödeme, stok, onay) koordine eden servis; para veya stok tutmaz, kararları sıralar.
Provider Gateway nedir?
Gerçek ödeme sağlayıcısını (PSP) uygulama iç modeline çeviren soyutlama katmanı.
"Ödeme akışı = tek bir servisin fonksiyonu" doğru mu?
Ödeme akışı = birden fazla bağımsız servisin katıldığı bir koordinasyon
Bu bölüm neyi sabitler?
Bu yazı, ödeme akışını neden “bir servisin fonksiyonu” gibi değil, dağıtık bir sistem problemi gibi tasarlamanız gerektiğini anlatıyor. Bir ödeme, tek bir servisin işlemi değildir; sepet, stok, provider gateway ve finansın aynı gerçek üzerinde anlaştığı bir koordinasyondur. Bir e-ticaret platformunda “ödeme al” dediğinizde aslında beş farklı sistemin aynı gerçek üzerinde anlaşmasını istersiniz: sepet dondurulmuş mu, stok var mı, provider gateway parayı aldı mı, sipariş onaylandı mı, finans kaydı doğru mu. Bunların hepsi tek bir process içinde, tek bir transaction'da yaşamaz.
Ogrenilen Muhendislik Prensipleri
- Bir ödeme akışı, tek servisin fonksiyonu değil; birden fazla bağımsız sistemin koordinasyonudur.
- PSP, sizin transaction sınırınızın dışındadır; onunla event sözleşmesiyle konuşulur, senkron kilitle değil.
- Eventual consistency bir zayıflık değil, ağın ve dış sağlayıcıların gerçek davranışının tasarıma yansımasıdır.
Okumaya devam et
Okumaya devam et
Seride sonraki yazi
Ödeme Durum Makinesi Tasarımı: Checkout ve Payment Neden Aynı Şey Değildir?
Ödeme Succeeded olması, siparişin Completed olduğu anlamına gelmez. Checkout ve payment yaşam döngülerini ayırmazsanız, üretimde iki gerçek çakışır.
Ayni seriden
Neden Tahsilat (Capture) Kolay, Sonuçlandırma (Finalization) Zordur?
PSP'nin parayı alması bir tek adımdır. Siparişi bitirmek; stok, finans, bildirim ve temizlik adımlarının hepsinin başarılı olmasını gerektiren bir saga'dır.…
Ayni seriden
Değişmez Ödeme Snapshot Tasarımı: Sepeti Donduran Karar
Ödeme başlarken sepeti canlı okumak, tutarı ve para birimini kararsız bırakır. Intent anında donan bir snapshot olmadan finalization güvenilir çalışmaz.