Oyun Kitabı

Production'da CQRS (Command Query Responsibility Segregation): Tutarlılık, Hatalar ve Kurtarma Stratejileri (Productionda CQRS Tutarlilik Hatalar Ve Kurtarma Stratejileri)

CQRS production ortamında nasıl güvenli çalışır? Consistency lag, duplicate event, sıra bozulması, projection recovery, retry, DLQ ve Saga stratejileri.

CQRS production recovery flow for retries, projections, and consistency

Bu hatalar kullanıcıya nasıl görünür?

Bir banka uygulamasında bakiye iki saniye gecikirse kullanıcı paranın kaybolduğunu düşünebilir. Buna karşılık bir beğeni sayısının iki saniye gecikmesi çoğu kullanıcı için kabul edilebilir olabilir. Aynı teknik gecikme, iki farklı ürün riskidir.

Benzer şekilde aynı OrderPlaced mesajı ikinci kez gelirse stok iki kez azalabilir. Bu yüzden production'daki kavramları yalnızca tanım olarak değil, kullanıcıya ve işe etkisi üzerinden okumak gerekir.

Production'da asıl soru

Mutlu yol basittir: command kabul edilir, event yayınlanır, projection güncellenir. Production'da ise mesaj iki kez gelir, consumer geride kalır, projection bozulur veya kullanıcı yazdığı siparişi listede göremez.

Command accepted → event published → projection delayed → user refreshes
"Siparişim kayboldu mu?"

Dağıtık sistemlerde kısmi arıza istisna değildir. Bu yazı, hatayı yok etmeye değil; hata geldiğinde veri doğruluğunu, kullanıcı güvenini ve kurtarma süresini nasıl koruyacağımıza odaklanır.

Kavramlar ilk geçtiği yerde

📦 Consistency lag
Write başarılı olduktan sonra read modelin güncellenmesine kadar geçen süre.

📦 Retry
Geçici teknik hatada aynı işi kontrollü biçimde yeniden deneme.

📦 Dead-letter queue (DLQ)
Normal akışta işlenemeyen mesajların incelenmek üzere ayrıldığı kuyruk.

📦 Checkpoint
Projection'ın güvenle işlediği son event konumu.

Eventual consistency, verinin yanlış olduğu anlamına gelmez; farklı modellerin aynı gerçeğe farklı anlarda ulaşmasıdır. Bu kabul edilebiliyorsa ürün bunu kullanıcıya doğru anlatmalı, kabul edilemiyorsa kritik sorgu için farklı bir tutarlılık stratejisi seçmelidir.

Her savunma hattının bir nedeni var

  • Checkpoint tutulur; çünkü replay başladığında projection'ın güvenle nereden devam edeceğini bilmek isteriz.
  • Idempotency gerekir; çünkü duplicate event'in ikinci kez etkisini uygulamak stok veya ödeme gibi gerçek iş sonuçlarını bozar.
  • Retry sınırlanır; çünkü bozuk bir mesajı tekrar denemek onu düzeltmez, yalnızca yükü ve yanlış etkiyi büyütebilir.
  • DLQ kullanılır; çünkü normal akışta çözülemeyen mesajın sahipliğini ve incelemesini görünür kılmak gerekir.
  • Partition key aggregate ID olur; çünkü aynı aggregate'in olay sırası, global olay sırasından daha önemlidir.
  • Replay yapılır; çünkü projection bozulsa bile doğrulanmış event geçmişi hâlâ doğru kaynaktır.

Tutarlılık gecikmesi teknik değil, ürün kararıdır

Bir ödeme alındıktan sonra sipariş listesinde iki saniye görünmemesi kullanıcı için veri kaybı gibi hissedilebilir. Önce görünür sözleşmeyi belirleyin: İşlemden sonra hangi ekran ne kadar sürede güncel olmalı?

POST /orders → 202 Accepted + orderId + version
GET /orders/{id}?minVersion=42
  → projection 42'ye ulaştıysa güncel görünüm
  → henüz ulaşmadıysa "işleniyor" durumu

Optimistic UI, polling veya wait-for-version kullanılabilir. Bunlar lag'i sıfırlamaz; çünkü asıl iş kullanıcıya gecikmenin anlamını dürüstçe göstermektir. Kritik kararlar için command tarafının sonucu kaynak gerçek olmaya devam eder.

Duplicate event ve sıra bozulması

At-least-once teslimat aynı mesajın tekrarını normalleştirir. Aynı sipariş event'ini ikinci kez işlemek stok sayısını iki kez azaltabilir. Consumer event kimliğini ve aggregate sürümünü kontrol etmelidir.

if event.id already processed: ignore
if event.version <= projection.version: ignore
apply event
store checkpoint and event id

Bu kontrol indexed lookup ile O(1) ortalama veya O(log n) maliyet taşır. Sıralama yalnızca partition içinde garanti ediliyorsa partition key aggregate ID olmalıdır; çünkü aynı siparişin nedensel sırası global sıradan önemlidir.

Retry, DLQ ve operatörün karar anı

Her hata tekrar denenmemelidir. Ağ zaman aşımı geçici olabilir; geçersiz event şeması kalıcı hatadır.

Hata türü Tepki Neden
Timeout / 503 Exponential backoff ile retry Bağımlılık toparlanabilir
Rate limit Gecikmeli retry Yükü büyütmeden toparlanmak
Şema doğrulama hatası DLQ + alarm Retry mesajı düzeltemez
İş kuralı ihlali Kaydet, incele, telafi et Otomatik retry yanlış etkiyi büyütebilir

DLQ çöplük değildir. Her mesajın owner'ı, inceleme süresi, replay prosedürü ve alarmı olmalıdır.

Projection bozulursa nasıl kurtarılır?

Projection cache değil, yeniden üretilebilen iş görünümüdür.

1. Consumer'ı durdur veya yeni projection sürümü oluştur
2. Son güvenli checkpoint'i doğrula
3. Event stream'i kontrollü replay et
4. Sayım ve örnek veri doğrulaması yap
5. Trafiği yeni projection'a yönlendir
6. Lag ve hata oranını izle

Replay maliyeti event sayısıyla doğrusal O(n)'dir. Snapshot veya segmentli replay bunu azaltabilir; ama snapshot kaynak gerçek değildir. Çünkü kurtarmada güvenilecek kayıt, doğrulanmış event geçmişidir.

Saga'nın başarısızlık yolu

E-ticarette ödeme başarısız olduğunda stok sonsuza kadar rezerve kalmamalıdır. Saga teknik rollback değil, iş anlamı taşıyan telafidir.

Reserve inventory → Capture payment → Create shipment
                 payment fails → Release inventory

Telafi de idempotent olmalıdır: ReleaseInventory iki kez çalışırsa stok iki kez artmamalıdır. Choreography küçük yerel akışlarda hafiftir; orchestration çok adımlı süreçte state machine ve tek izleme noktası sağlar.

Gözlemlenebilirlik

Consumer lag, retry sayısı, DLQ derinliği, checkpoint yaşı, duplicate oranı ve uçtan uca işlem süresini ölçün. Trace ID'yi command'den event'e, consumer'a ve kullanıcıya dönen query'ye taşıyın. Alarm teknik metrikte değil kullanıcı etkisinde anlam kazanır.

Yanlış güven duygusu oluşturan eşleştirmeler

❌ Retry = güvenilirlik
✓ Retry, yalnızca geçici hatada ve idempotent işlemde güvenlidir.

❌ DLQ = kurtarma
✓ DLQ, inceleme ve replay sürecinin başlangıcıdır.

❌ Replay = her zaman güvenli
✓ Sürümleme ve yan etkiler ayrılmadan replay etkiyi tekrar üretebilir.

❌ Eventual consistency = rastgele gecikme
✓ Gecikme ölçülmeli, ürünle kabul edilmeli ve kullanıcıya açıklanmalıdır.

Production readiness kontrolü

  1. Kullanıcıya görünen consistency lag için hedefiniz var mı?
  2. Consumer duplicate ve out-of-order event'lerde güvenli mi?
  3. Retry politikası geçici ve kalıcı hataları ayırıyor mu?
  4. DLQ mesajının owner'ı ve replay runbook'u tanımlı mı?
  5. Projection'ı production verisi üzerinde güvenle yeniden kurabiliyor musunuz?
  6. Saga telafileri idempotent mi?

Bu soruların her birine kanıtla cevap veremiyorsanız sistem ölçeklenebilir görünebilir; ancak henüz işletilebilir değildir.

Bu yazıdan aklında ne kalmalı?

  1. Eventual consistency, kullanıcı deneyimiyle yönetilmesi gereken bir sözleşmedir.
  2. Duplicate ve sıra bozulması edge case değil, dağıtık teslimatın normalidir.
  3. Retry, DLQ ve replay birlikte tasarlanmış bir kurtarma sistemidir.
  4. Projection yeniden kurulabilir değilse operational debt'e dönüşür.
  5. Saga rollback yapmaz; iş etkisini telafi eder.

Production mimarisi, mesajlar ilk seferde doğru geldiğinde değil; iki kez, geç veya beklenmedik sırada geldiklerinde nasıl davrandığınızda görünür.

SSS

Sık sorulan sorular

Consistency lag nedir?

Write başarılı olduktan sonra read modelin güncellenmesine kadar geçen süre.

Retry nedir?

Geçici teknik hatada aynı işi kontrollü biçimde yeniden deneme.

"Retry = güvenilirlik" doğru mu?

Retry, yalnızca geçici hatada ve idempotent işlemde güvenlidir.

Bu bölüm neyi sabitler?

Dağıtık sistemlerde kısmi arıza istisna değildir. Bu yazı, hatayı yok etmeye değil; hata geldiğinde veri doğruluğunu, kullanıcı güvenini ve kurtarma süresini nasıl koruyacağımıza odaklanır. Eventual consistency, kullanıcı deneyimiyle yönetilmesi gereken bir sözleşmedir. Mutlu yol basittir: command kabul edilir, event yayınlanır, projection güncellenir. Production'da ise mesaj iki kez gelir, consumer geride kalır, projection bozulur veya kullanıcı yazdığı siparişi listede göremez.

Ogrenilen Muhendislik Prensipleri

  • Tutarlılık gecikmesi, ürün tarafından kabul edilmiş ve kullanıcıya görünür bir sözleşme olmalıdır.
  • Duplicate, sıra bozulması ve replay için idempotent consumer tasarımı zorunludur.
  • Kurtarma; checkpoint, runbook ve gözlemlenebilirlikle önceden tasarlanmış bir yetenektir.

Okumaya devam et

Okumaya devam et

Ilgili yazilar

Ilgili yazilar

Ilgili yazilar

Paylaş