Modern yazılım sistemleri giderek daha karmaşık, dağıtık ve yüksek duyarlılık gerektiriyor. Geleneksel senkron istek-yanıt modelleri bu taleplerle mücadele ederken, sıkı bağlı hizmetlere ve darboğazlara yol açıyor. İşte Olay Odaklı Mimari (EDA). Üreticileri ve tüketicileri olaylar üzerinden ayırarak EDA, sistemlerin daha ölçeklenebilir, dayanıklı ve uyarlanabilir olmasını sağlar. Bu yazıda, mesaj aracıları, olay kaynağı ve Komut Sorgu Sorumluluk Ayrımı (CQRS) dahil olmak üzere sağlam bir olay odaklı ekosistemi oluşturan temel bileşenlere derinlemesine ineceğiz.
Mesaj Aracıları ile Ayrışmanın Gücü
Her olay odaklı sistemin kalbinde mesaj aracıları yer alır. Aracı, üreticiler ile tüketiciler arasında mesajları kabul eden, depolayan ve yönlendiren ara bir işlev görür. RabbitMQ, Apache Kafka ve AWS SQS gibi popüler aracılar; kalıcılık, dayanıklılık ve ölçeklenebilirlik gibi temel özellikleri sağlar. Burada kilit avantaj gevşek bağlılıktır; bir hizmet, olaylarını kimin veya neyin tükettiğini bilmek zorunda değildir. Bu durum, ekiplerin hizmetleri bağımsız olarak dağıtmasına ve sistemin belirli kısımlarını yüke göre ölçeklendirmesine olanak tanır.
Örneğin, bir e-ticaret sipariş hizmetini ele alalım. Bir sipariş verildiğinde, OrderCreated (Sipariş Oluşturuldu) olayını yayınlar. Ödeme hizmeti, envanter hizmeti ve bildirim hizmeti, sipariş hizmetinin varlıklarından haberdar olmasına gerek kalmadan bu olaya abone olabilir.
Olay Kaynağı: Gerçeğin Kaynağı
Olay Kaynağı (Event Sourcing), bir uygulamanın durumunun yalnızca mevcut durumundan ziyade, değişmez olayların bir dizisi tarafından belirlendiği bir tasarım desenidir. Bir değişikliğin yalnızca nihai sonucunu (geleneksel CRUD işlemlerinde olduğu gibi) kaydetmek yerine, her değişikliği bir olay olarak kaydederiz.
Bu yaklaşım birkaç avantaj sunar:
- Denetlenebilirlik: Tüm değişikliklerin eksiksiz bir geçmişine sahip olursunuz.
- Hata Ayıklama: Hataları yeniden üretmek için olayları yeniden oynatabilirsiniz.
- Zamansal Sorgular: Sistemin herhangi bir anındaki durumunu yeniden oluşturabilirsiniz.
Aşağıda, olayların nasıl depolanıp alınabileceğini gösteren basitleştirilmiş bir Java kavramsal örneği bulunmaktadır:
public class OrderAggregate {
private List events = new ArrayList<>();
public void placeOrder(Order order) {
events.add(new OrderCreatedEvent(order.getId(), order.getItems()));
saveEventsToStream(events);
}
public List getHistory() {
return Collections.unmodifiableList(events);
}
}
CQRS: Okumaları Yazmalardan Ayırma
Komut Sorgu Sorumluluk Ayrımı (CQRS), olay kaynağını tamamlar; verileri okuyan işlemleri (sorgular) verileri değiştiren işlemlerden (komutlar) ayırır. Geleneksel bir mimaride, her iki işlem için tek bir veritabanı modeli kullanılır. CQRS'de ise hızlı sorgulama için okuma modelini (örneğin Elasticsearch kullanarak) optimize ederken, tutarlılık ve eşzamanlılık için yazma modelini optimize etmeye devam edebilirsiniz.
Bu ayrım, okuma kalıplarının yazma kalıplarından önemli ölçüde farklı olduğu yüksek veri akışlı sistemlerde hayati önem taşır. Örneğin, ürün listelemeleri için saniyede milyonlarca okuma, ancak envanter güncellemeleri için yalnızca yüzlerce yazma işlemi yapabilirsiniz. CQRS, bu işlemlerin bağımsız olarak ölçeklendirilmesine olanak tanır.
Tepkisel İş Akışları Oluşturma
Tepkisel mimariler, engelleme yapmayan asenkron davranışı vurgular. Olayları, asenkron iş akışlarını ve tepkisel akışları birleştirerek sistemler, daha az kaynakla yüksek eşzamanlılığı yönetebilir. Akka veya Project Reactor gibi çerçeveler, geliştiricilerin gerçek zamanlı değişikliklere tepki veren asenkron boru hatlarını oluşturmasına olanak tanır.
Bu desenleri entegre ederken, hataları zarif bir şekilde yönetmek hayati önem taşır. Kimliklilik (Idempotency) anahtardır; tüketiciler, veri bozulmasına neden olmadan aynı olayı birden fazla kez işleyebilmelidir. Bu durum genellikle benzersiz olay kimlikleri kullanılarak ve bunların tüketiciye özgü bir depoda izlenerek sağlanır.
Sonuç
Olay Odaklı Mimari, Olay Kaynağı ve CQRS ile birleştirildiğinde, modern, ölçeklenebilir ve dayanıklı sistemler oluşturmak için güçlü bir araç seti sağlar. Geleneksel monolitik tasarımlara kıyasla karmaşıklık artsa da, esneklik, performans ve sürdürülebilirlik açısından sağladığı faydalar büyüktür. Orta ve ileri düzey geliştiriciler için, günümüzün bulut-native ortamındaki dağıtık bilişim zorluklarıyla başa çıkmak adına bu desenleri ustalaşmak esastır.