📌 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:
- Gecikme Toplamı: Her servisin 100 ms gecikmesi toplam süreyi 400 ms’ye çıkarır.
- Kaskat Çökme: Zincirdeki tek bir servis (örneğin Kargo) 500 hatası verirse veya yavaşlarsa, tüm sipariş akışı çöker.
- 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
- Cloud-Native Mimarilerde Dağıtık İzleme ve OpenTelemetry — Asenkron mesajların servisler arası takibi.
- Docker ve Container Kaynak İzolasyonu — Kafka broker ve ZooKeeper küme container’ları.
- Tasarım Kalıpları ve Gerçek Dünya Uygulamaları — Observer ve Strategy kalıplarının dağıtık karşılığı.
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.