📌 Hızlı Özet & Temel Çıkarım:
Olay Odaklı Mimari (Event-Driven Architecture - EDA), mikroservislerin senkron HTTP/REST çağrıları yerine asenkron mesajlaşma broker’ları (Apache Kafka veya RabbitMQ) üzerinden iletişim kurduğu yüksek ölçeklenebilir bir dağıtık sistem modelidir. Servislerin birbirinin IP adresini veya anlık durumunu bilme zorunluluğunu ortadan kaldırarak; kaskat çökmeleri (cascading failures) önler, trafik dalgalanmalarını tamponlar ve yatayda sonsuz büyüme imkanı tanır.


1. Senkron REST Çağrılarının Dağıtık Sistemlerdeki Tehlikesi

Mikroservis mimarisine geçen ekiplerin en sık düştüğü hata, eski monolitik fonksiyon çağrılarını HTTP istekleriyle değiştirmektir.

Örneğin: Bir kullanıcı sipariş verdiğinde Sipariş Servisi -> Stok Servisi -> Ödeme Servisi -> Kargo Servisi zincirleme senkron HTTP istekleriyle birbirini beklerse:

  1. Gecikme Toplamı: Her servisin 100 ms gecikmesi toplam süreyi 400 ms’ye çıkarır.
  2. Kaskat Çökme: Zincirdeki tek bir servis (örneğin Kargo) 500 hatası verirse veya yavaşlarsa, tüm sipariş akışı çöker.
  3. Kilitlenme: Yüksek trafikte bağlantı havuzları (connection pools) hızla tükenir.

Olay Odaklı Mimaride Sipariş Servisi veritabanına kaydı atar atmaz OrderCreated olayını mesaj kuyruğuna fırlatır ve kullanıcıya hemen 202 Accepted yanıtı döner. Diğer tüm servisler bu olayı kendi hızlarında tüketir.


2. Kafka vs RabbitMQ: Doğru Aracı Seçmek

Her iki mesajlaşma teknolojisi de farklı problemlere odaklanır:

Kriter Apache Kafka RabbitMQ
Model Dağıtık Olay Kayıt Günlüğü (Log Stream) Gelişmiş Mesaj Kuyruğu (AMQP Broker)
Mesaj Saklama Disk üzerinde günlerce/aylarca saklanır Tüketilen mesaj kuyruktan silinir
Akış Hızı (Throughput) Milyonlarca mesaj / saniye (Yüksek) On binlerce mesaj / saniye (Orta)
Yönlendirme (Routing) Basit Topic ve Partition Esnek Exchange (Topic, Direct, Fanout)
Kullanım Alanı Telemetri, Finansal Olaylar, Event Sourcing Görev Kuyrukları (Task Queue), Bildirimler

3. Transactional Outbox Pattern ile Çifte Yazma Sorununu Çözme

Dağıtık sistemlerin en zor problemi “Veritabanına yaz ve ardından Kafka’ya mesaj at” ikilemidir. Eğer veritabanı işlemi başarılı olur fakat tam mesaj atılacağı anda sunucunun elektriği kesilirse, sistem tutarsızlığa düşer (Dual Write Problem).

Bu sorunu çözmek için Transactional Outbox Pattern uygulanır:

[İş Mantığı]

    ▼ (Tek bir yerel ACID Transaction içinde)
1. 'orders' tablosuna siparişi kaydet.
2. 'outbox' tablosuna 'OrderCreated' mesajını yaz.

    ▼ (Arka plan CDC aracı - Debezium / Poller)
'outbox' tablosunu oku -> Kafka'ya ilet -> İşlendi olarak işaretle

Bu model, mesajın en az bir kez (at-least-once) Kafka’ya ulaşacağını garanti eder.

Aşağıdaki Python örneği, Kafka tüketiminde mesajın çift işlenmesini önleyen idempotent tüketici mantığını gösterir:

import json
from confluent_kafka import Consumer

conf = {
    'bootstrap.servers': 'localhost:9092',
    'group.id': 'payment-processor',
    'auto.offset.reset': 'earliest',
    'enable.auto.commit': False # Manuel ofset onaylama
}
consumer = Consumer(conf)
consumer.subscribe(['order-events'])

processed_message_ids = set() # Gercek sistemde Redis / DB tabanli tutulur

def process_event():
    while True:
        msg = consumer.poll(1.0)
        if msg is None: continue
        if msg.error(): continue

        payload = json.loads(msg.value().decode('utf-8'))
        event_id = payload.get('eventId')

        # Idempotent Kontrol: Mesaj daha once islendi mi?
        if event_id in processed_message_ids:
            consumer.commit(msg)
            continue

        # Is mantigini yurut
        handle_payment(payload)
        
        # Basariyla tamamlandi, ofseti onayla
        processed_message_ids.add(event_id)
        consumer.commit(msg)

4. İlgili Konular ve İç Bağlantılar


5. Sıkça Sorulan Sorular

Kafka’da mesaj sırası (ordering) nasıl garanti edilir?

Kafka’da sıra garantisi küme genelinde değil, yalnızca aynı partition içinde geçerlidir. Eğer bir müşterinin tüm sipariş olaylarının sırayla işlenmesini istiyorsanız, mesajın key alanına customerId değerini atamalısınız. Kafka aynı anahtara sahip mesajları her zaman aynı partition’a yönlendirir.

Dead Letter Queue (DLQ) ne zaman devreye girmelidir?

Bir mesaj bozuk veri içeriyorsa veya işlenirken sürekli istisna (unhandled exception) fırlatıyorsa, tüketici kuyruğu tıkamamalıdır. Belirli bir yeniden deneme (retry count) sayısından sonra mesaj bir DLQ konusuna taşınır ve geliştiricilere uyarı gönderilir.

6. Dağıtık İşlemlerde Hata Yönetimi: Saga Deseni (Choreography vs Orchestration)

Olay odaklı mikroservis mimarilerinde geleneksel veritabanlarının sunduğu iki fazlı onaylama (Two-Phase Commit - 2PC) kullanılamaz; çünkü servisler farklı veritabanlarına (PostgreSQL, MongoDB vb.) sahiptir.

İşlemlerin tutarlılığını sağlamak için Saga Deseni devreye girer:

  • Koreografi (Choreography): Her servis bir olayı dinler, kendi işini yapar ve bir sonraki olayı fırlatır. Merkezi bir yönetici yoktur. Küçük sistemlerde hızlıdır ancak olay zinciri uzadıkça takip zorlaşır.
  • Orkestrasyon (Orchestration): Merkezi bir Saga Yöneticisi (Temporal veya Camunda gibi) adımları tek tek yürütür. Eğer adım 3’te (Ödeme Alındı) bir hata çıkarsa, yönetici geriye dönük telafi edici işlemleri (Compensating Transactions - örneğin Rezervasyonu İptal Et) otomatik olarak tetikler.

Bu mimari sayesinde bankacılık ve e-ticaret gibi sıfır hata toleransı gerektiren sistemlerde veri tutarlılığı matematiksel kesinlikle korunur.

7. Kafka Kümesinde Partition Sayısı ve Tüketici Grubu Ölçekleme Matematiği

Kafka mimarisinde bir topic’in partition sayısı, o topic’i aynı anda paralel olarak kaç tüketicinin (consumer) okuyabileceğini belirleyen üst sınırdır.

Eğer bir topic’te 6 partition varsa ve tüketici grubunuza 10 adet pod eklerseniz, bu 10 pod’un 4 tanesi tamamen boşta bekler (idle).

Doğru ölçekleme formülü:

  • Tüketici Sayısı: Her zaman partition sayısına eşit veya daha az olmalıdır.
  • Gecikme Takibi (Consumer Lag): Tüketicilerin üretime yetişemediği durumlarda Lag değeri yükselir. Prometheus ve Grafana alarmları ile Lag 1.000 mesajı aştığında HPA tetiklenmeli ve partition sayısı artırılmalıdır.