Sektörden Haberler

Transactional Outbox Pattern Nedir?

2 Kasım 2026 Pazartesi


Çift Yazma Krizine Son

Mikroservis ve dağıtık mimarilerde en sık karşılaşılan senaryolardan biri şudur: Kullanıcı yeni bir sipariş verir; servis bu siparişi kendi veri tabanına kaydeder ve ardından stok veya bildirim servislerinin haberdar olması için Kafka veya RabbitMQ gibi bir mesaj kuyruğuna olay (event) fırlatır.

Koda baktığınızda her şey son derece masum görünür:

  1. Veri tabanı transaction'ını başlat.
  2. Siparişi kaydet (DB.Save).
  3. Transaction'ı commit et.
  4. Mesaj kuyruğuna olayı gönder (Kafka.Produce).

Peki ya 3. adım ile 4. adım arasında sunucunun fişi çekilirse? Ya da veri tabanına kayıt atıldığı halde tam o milisaniyede ağ koptuğu için Kafka'ya ulaşılamazsa?

Sipariş veri tabanınızda kalır ama kargo veya fatura servisinin bundan asla haberi olmaz. Tam tersini yapıp önce Kafka'ya mesaj atıp sonra veri tabanına yazmayı denerseniz ve veri tabanı çökerse, bu sefer de var olmayan bir siparişin faturası kesilir.

İki farklı dağıtık sisteme (Veri tabanı + Mesaj Kuyruğu) aynı anda veri yazma zorunluluğunun yarattığı bu kronik açmaza yazılım mimarisinde Çift Yazma Problemi (Dual-Write Problem) denir.

İşte bu riski matematiksel kesinlikle ortadan kaldıran ve dağıtık mimarilerde güvenilir veri akışını garanti eden tasarım kalıbı: Transactional Outbox Pattern.

Transactional Outbox Pattern Nedir?

Transactional Outbox Pattern; bir iş nesnesini (örneğin Sipariş) veritabanına kaydederken, dış dünyaya gönderilecek mesajı da aynı yerel veri tabanı transaction'ı (ACID) içinde özel bir "Giden Kutusu" (Outbox) tablosuna yazan ve ardından bu mesajları asenkron bir süreçle mesaj kuyruğuna aktaran güvenilir bir mimari desendir.

Bu yaklaşımda mesaj kuyruğuna doğrudan ağ üzerinden yazmaya çalışmazsınız. Mesajı veri tabanındaki geçici bir tabloya yazar, işinizi sağlama alır ve mesajın iletim sorumluluğunu arka planda çalışan güvenilir bir aktarıcıya (Message Relay) devredersiniz.

Outbox Tablosundaki Mesajlar Kuyruğa Nasıl Taşınır?

Mesajları Outbox tablosuna yazmak işin ilk yarısıdır. İkinci yarısı ise bu kayıtları okuyup mesaj broker'ına iletmektir. Bu işlem için endüstride iki yöntem kullanılır:


1. Polling Publisher (Periyodik Sorgulama)

Arka planda çalışan bir cron işi veya worker servis, veri tabanındaki Outbox tablosunu saniyede bir sorgular (SELECT * FROM Outbox WHERE status = 'PENDING'). Okuduğu mesajları Kafka'ya basar ve ardından tablodaki durumu SENT olarak günceller ya da kaydı siler.

  • Artıları: Kurulumu basittir, ekstra harici altyapı gerektirmez.
  • Eksileri: Yüksek trafikli sistemlerde veri tabanını sürekli sorgulamak ek yük yaratır ve iletimde milisaniyelik gecikmelere yol açabilir.

2. Transaction Log Tailing / Change Data Capture (CDC)

Modern ve yüksek performanslı mimarilerin tercihidir. Veri tabanının ham işlem günlüklerini (PostgreSQL WAL, MySQL Binlog) doğrudan dinleyen bir araç (örneğin Debezium) kullanılır.


Nasıl Çalışır?:

Veri tabanına yeni bir Outbox satırı eklendiği an, Debezium bu değişikliği disk seviyesindeki logdan anında okur ve milisaniyeler içinde Kafka konusuna aktarır. Veri tabanına hiçbir sorgu maliyeti bindirmez.

Unutulmaması Gereken Kural: At-Least-Once Delivery ve Idempotency

Transactional Outbox Pattern, mesajın en az bir kez iletileceğini (at-least-once delivery) garanti eder. Ancak mesaj Kafka'ya başarıyla yazıldıktan hemen sonra aktarıcı servis çökerse, sistem ayağa kalktığında aynı mesajı bir kez daha kuyruğa gönderebilir.

Bu nedenle Outbox desenini kullanan sistemlerin tüketicileri (Consumer / Dinleyici servisler), önceki yazılarımızda ele aldığımız Idempotency prensibine göre tasarlanmalıdır. Tüketici servis, aynı olay mesajı ikinci kez geldiğinde işlemi tekrar yürütmemeli ve durumu korumalıdır.