Event-Driven Architecture Nedir? Olay Tabanlı Mimari Rehberi
Servisleriniz birbirine sıkı sıkıya bağlı mı? Bir servisdeki değişiklik diğerlerini mi etkiliyor? Event-Driven Architecture ile servislerinizi olaylar üzerinden gevşek bağlayın, ölçeklenebilir ve esnek bir sistem kurun.
Tanım
Event-Driven Architecture (EDA), sistem bileşenlerinin olaylar (events) aracılığıyla haberleştiği bir mimari stildir. Bir şey olduğunda (sipariş verildi, ödeme alındı, stok güncellendi) ilgili servisler bu olayı dinler ve tepki verir.
Geleneksel: Sipariş Servisi → Ödeme Servisini çağır → Stok Servisini çağır → Bildirim Servisini çağır
EDA: Sipariş Servisi → "SiparişVerildi" olayı yayınla
↓
Event Bus
↓ ↓ ↓
Ödeme Servisi Stok Servisi Bildirim Servisi
EDA Bileşenleri
Event (Olay)
Sistemde gerçekleşen bir değişikliğin kaydı:
interface OrderPlacedEvent {
eventId: string;
eventType: 'OrderPlaced';
timestamp: string;
data: {
orderId: string;
customerId: string;
items: Array<{ productId: string; quantity: number }>;
totalAmount: number;
};
}
Event Producer
Olayı üreten servis.
Event Consumer
Olayı dinleyen ve tepki veren servis.
Event Channel (Bus/Broker)
Olayları taşıyan altyapı (Kafka, RabbitMQ, Redis Pub/Sub).
EDA Desenleri
1. Event Notification
Sadece "bir şey oldu" bilgisi gönderilir. Detay için tüketici kaynağa sorar.
{ "eventType": "OrderPlaced", "orderId": "123" }
2. Event-Carried State Transfer
Tüm ilgili veri olayla birlikte gönderilir. Tüketici ek sorgu yapmaz.
{
"eventType": "OrderPlaced",
"orderId": "123",
"customerId": "42",
"items": [...],
"totalAmount": 1500
}
3. Event Sourcing
Mevcut durumu saklamak yerine, tüm olayları sırasıyla saklayın. Mevcut durumu olayları tekrarlayarak (replay) elde edin.
Event 1: SiparişOluşturuldu { id: 123, items: [...] }
Event 2: ÖdemeAlındı { id: 123, amount: 1500 }
Event 3: KargoGönderildi { id: 123, trackingId: "TR123" }
→ Mevcut durum: Sipariş 123, Ödendi, Kargoda
Pratik Örnek
Producer (Sipariş Servisi)
class OrderService {
async placeOrder(customerId: string, items: CartItem[]) {
const order = Order.create(customerId, items);
await this.orderRepo.save(order);
// Olayı yayınla
await this.eventBus.publish({
eventType: 'OrderPlaced',
data: {
orderId: order.id,
customerId,
items,
totalAmount: order.total
}
});
return order;
}
}
Consumer (Bildirim Servisi)
class NotificationService {
@OnEvent('OrderPlaced')
async handleOrderPlaced(event: OrderPlacedEvent) {
await this.emailService.send({
to: event.data.customerId,
template: 'order-confirmation',
data: { orderId: event.data.orderId }
});
}
}
Eventual Consistency
EDA'da veriler anında değil, sonunda tutarlı olur:
T0: Sipariş verildi ✅
T1: Ödeme alındı ✅ (100ms sonra)
T2: Stok güncellendi ✅ (200ms sonra)
T3: E-posta gönderildi ✅ (500ms sonra)
Bu, güçlü tutarlılık (strong consistency) yerine eventual consistency tercih etmek anlamına gelir.
Ne Zaman EDA Kullanmalı?
✅ Kullanın:
- Birden fazla servisin aynı olaya tepki vermesi gerektiğinde
- Gevşek bağlantı ve bağımsız ölçeklenebilirlik istediğinizde
- Audit trail / event log gerekliyse
- Asenkron iş akışları varsa
❌ Kullanmayın:
- Basit CRUD uygulamalarında
- Anında tutarlılık (strong consistency) gerektiğinde
- Az sayıda servis varsa
Best Practices
- Idempotent consumer yazın — Aynı olay tekrar geldiğinde sorun çıkmamalı
- Schema versioning — Event şemasını versiyonlayın
- Dead Letter Queue — İşlenemeyen olayları ayırın
- Correlation ID — Olayları takip etmek için unique ID kullanın
- Event ordering — Sıralama önemliyse partition key kullanın
- Monitoring — Event lag ve tüketim hızını izleyin
Sonuç
Event-Driven Architecture, dağıtık sistemlerde gevşek bağlantı, ölçeklenebilirlik ve esneklik sağlar. Eventual consistency trade-off'unu kabul etmeniz gerekir, ama doğru uygulandığında güçlü ve dayanıklı sistemler kurmanızı sağlar.
Event-driven mimariyi LabLudus platformunda interaktif olarak öğrenin.