Event Sourcing Neydi?

07.11.2022 | dakika okuma

Önceden servislerimiz aşağıdaki gibi olurdu.

Application Services 01

Bu servisimiz yüzlerce satır koddan oluşurdu. Bu karmaşadan kurtulmak için CQRS ile servislerimizi "Command" ve "Query" olmak üzere ikiye böldük. CRUD işlemlerimizi "Command" servisleri ile, sorgulama işlemlerimizi "Query" servisleri ile yaptık. Ortaya aşağıdaki gibi iki ayrı servis çıktı.

Application Services 02

Bu şekilde az da olsa okunabilirlik sağlamış olduk ama halen god class'lar ortaya çıkıyordu. Mediator ile birlikte "UseCase"ler hayatımıza girdi. Bu sefer her bir "UseCase" için ayrı handler'lar oluşturmaya başladık. Ortaya aşağıdaki gibi 13 ayrı handler çıktı.

Application Services 03

Bu yaklaşım ile her bir handler sadece kendi işini yapar oldu. Kod satırları daha da azaldı, okunabilirlik daha da arttı. Bu da bize kolay yönetilebilirlik sağladı.

Bu sefer performans üzerinde çalıştık. Ortaya çıkan her veritabanı teknolojisi farklı özellikler sunuyordu. Kimisinin yazma hızı çok iyiydi, kimisinin okuma hızı. Madem her şeyi böldük… "Command" işlemleri için yazma hızı iyi veritabanı teknolojilerini, "Query" işlemleri için okuma hızı iyi veritabanı teknolojilerini seçtik. Ortada bir sorun vardı. İki farklı veritabanı teknolojisindeki verileri senkronize etmemiz gerekiyordu.

Bu noktada "Messaging" teknolojileri imdadımıza yetişti. Command handler'da verileri veritabanına yazdıktan sonra aynı verileri kuyruklara mesaj olarak gönderdik. O kuyrukları dinleyen consumer'lar yazdık. Consumer'lar ile gelen mesajları "Query" işlemleri için seçtiğimiz veritabanına aktardık. Bu şekilde iki farklı veritabanı teknolojileri arasında senkronizasyon sağladık.

Daha sonra her şeyin CRUD olmadığını anladık. Her şey veriyi eklemek, güncellemek ve silmek değildi. Neyi güncelliyorduk?

Meetup uygulamasını düşünelim.

Örneğin bir etkinlik tanımlıyoruz. Bu bir insert'dir.

Etkinliği tanımladıktan sonra etkinlik içeriğini güncelleyebiliyoruz. Bu bir update'dir.

Etkinliğe katılmayı düşünenler etkinliğe gideceklerini belirtiyor. Bu etkinlik için update midir? Update değilse nedir?

Etkinlik başlamadan 1 saat önce etkinliğe kayıt alınmaması için etkinliğin durumunu "Stopped" olarak işaretliyoruz. Peki bu bir update midir?

Etkinlik sona erdikten sonra etkinliğin durumunu "Completed" olarak işaretliyoruz. Peki bu update midir?

Etkinlik sahibi olarak etkinliğe fotoğraflar yüklüyoruz. Bu da mı update'dir?

Etkinliğe katılanlar etkinliğe yorum giriyorlar. Update mi sizce?

Gördüğünüz gibi her şey Insert, Update ve Delete olarak düşünülemezdi. Aslında her şey aşağıdakiler gibi bir event'ti.

    • MeetupRegistered
    • MeetupJoined
    • MeetupStopped
    • MeetupCompleted
    • MeetupAddedPhoto
    • MeetupAddedComment

Her şey bir event ise verilerimizi klasik yöntemdeki gibi ilişkili tablolarda satırlar halinde tutmaya gerek yoktu. O zaman aşağıdaki görseldeki gibi bir tane tablo oluşturup her event'i bu tabloya bir satır olarak ekledik.

Events Table

Baktığımızda tanımladığımız etkinlik bu satırların birleşiminden ibaret. Her bir event'in versiyon numarası var. Aşağıdan yukarıya doğru birleştirerek çıktığımızda aşağıdaki gibi bir sonuç ortaya çıkıyor.

Tanımladığımız etkinlik; bilgileriyle, fotoğraflarıyla, yorumlarıyla bir bütün olarak "Aggregate"i temsil eder. Bu sebeple AggregateId bilgisi bulunuyor.

"Command" işlemlerinde verilerimizi yukarıdaki gibi event olarak bir veritabanına kaydediyoruz dedik. Fakat bu satırlarda sorgulama yapamayacağımız için bu event'leri aynı zamanda "Query" için seçtiğimiz veritabanına da yazmamız gerekli. Örneğin; meetup uygulamasında "tamamlanmamış etkinlikleri" göstermek istediğimiz zaman yukarıdaki event'lerde bir sorgulama yapamayız.

Önceki paragraflarda bahsettiğim gibi etkinlik bilgilerini "Command" işlemlerinde veritabanına event olarak yazdıktan sonra bu bilgileri bir "messaging" kuyruğuna göndermeliyiz. Bu kuyruğu dinleyen bir consumer yazmalıyız. Bu consumer aracılığıyla "MeetupRegistered" event'lerini dinleyip gerekli bilgiler ile "Query" veritabanına etkinlik bilgilerini yazmalıyız. Yine aynı şekilde "MeetupCompleted" event'lerini de dinleyip "Query" veritabanından eklinlik bilgilerini silmeliyiz.

Event Sourcing Diagram

Yukarıda da gördüğünüz gibi "Command" bölgesinde API'den gelen event'ler event store'a yazılır. Bu event'ler aynı zamanda kuyruğa gönderilir. "Projection" bölgesinde kuyruktaki mesajlar işlenerek query store'a yazılır. "Query" bölgesinde sorgulama işlemleri yapılarak API'den sonuç döndürülür.

Event Sourcing dediğimiz şey tam olarak budur. Aggregate, Projection, Snapshot vb. gibi kendine has terimleri var. Peki "Command" için, "Messaging " için ve "Query" için seçeceğimiz teknolojiler ne olabilir?

Event'ler için "MSSQL" kullanılabilir. "Messaging" için "RabbitMQ" kullanılabilir. "Query" için ise "RavenDB, ElasticSearch, Couchbase" gibi teknolojiler kullanılabilir. Fakat Event Sourcing için .NET dünyasında "Event Store" adında bir teknoloji var. Bu teknoloji "Aggregate" ve "Projection" için çözüm sunmaktadır. Yani event'leri kaydedebileceğimiz store'u sağlamakla birlikte "Query" veritabanlarına kayıt atabilmemiz için gerekli olan "Messaging" ve "Projection" hizmetini de sağlamaktadır.

Event Store - Event Sourcing Database

Persist your application data as streams of events with our open-source database, EventStoreDB. We believe it’s the best data storage solution for event-sourced systems. Available for free download on most platforms or use our managed service Event Store Cloud.

Blog'umda teorik bilgilerden çok pratiğe yer veriyorum. Yani Tutorial tarzı yazılar yazmayı tercih ediyorum. Fakat Event Sourcing için öncesinden teorik bilgi aktarmak istedim. Yakın zamanda teoriyi pratiğe dökeceğimiz bir video ile karşınıza gelmek niyetindeyim. O video'da uzun uzadıya şu nedir bu nedir gibi konulara girmeden örnek bir uygulama geliştireceğim. Bu sebeple bu teorik yazı ile video'ya temel hazırlamak istedim.

Kolay gelsin.

Yazıyı Paylaş

Yorumlar

3 yıl önce
Emeklerinize sağlık.

Çok güzel bir anlatım olmuş. Karşımıza çıkacak canavarları, ve bu canavarları yenmek için izlenebilecek yöntemleri kısa ve öz bir şekilde betimlemişsiniz.

Biraz geç keşfettim ama büyük bir merakla okumaya devam edeceğim yazılarınızı.

Kolay gelsin.
Yanıtla
Ferit Güleç
4 yıl önce
Merhabalar, Saga kullanmak varken neden tüm etkinlikleri store etmeliyiz.?
Yanıtla
ahmetkucukoglu
4 yıl önce
Merhaba,

Herhangi bir serviste hata olması durumunda sistemi tutarlı hale getirebilmek adına bir dizi işlemi gerçekleştirmek için saga pattern'ini kullanıyoruz. Özetle asıl amaç rollback ve retry mekanizmaları ile hizmetler arası tutarlığı sağlamak. Business'a göre değişkenlik gösterebilir ama bunu uygulamak uygulama içerisindeki karmaşıklığı artırabilir. Ayrıca saga sürecindeki iş bittiğinde event'ler kaybolacaktır.

Event Sourcing her şeyi bir event olarak kaydettiği için atomic'liği çok basit bir şekilde sağlıyor. En önemlisi herhangi bir zamanda uygulamanın state'ini olayları baştan sona tekrar uygulayarak yeniden oluşturmasına imkan vermesi. Bu da canlı ortamda ortaya çıkan geçici hataların telafisine imkan verir.
Yanıtla
Tufan
4 yıl önce
Gerçekten mükemmel tek kalemde soluksuz okudum. Bahsettiğin video ne zaman gelecek?
Yanıtla
ahmetkucukoglu
4 yıl önce
Merhaba,

Teknik sebeplerden dolayı video konusunda henüz sonuç alamadım. Sözüm yerde kalmasın diye de videoda anlatacaklarımı seri yazı halinde yazmak istedim. Şimdilik iki seri yazıyı yazdım. Devamı gelecek.

İlginiz için teşekkür ederim.
Yanıtla
Süleyman Engin
4 yıl önce
Yazı için teşekkürler. Devamını bekliyorum.
Yanıtla
ahmetkucukoglu
4 yıl önce
Merhaba,

Ben teşekkür ederim. Event Store'un birinci bölümü ile devam edebilirsiniz. Diğer bölümleri de yakında yazacağım.

https://www.ahmetkucukoglu.com/asp-net-core-ile-event-sourcing-01-store/
Yanıtla

Yorum bırak

Yanıtla

Yanıtlamayı iptal et
Bu site reCAPTCHA tarafından korunmaktadır ve Google Gizlilik Politikası ve Hizmet Şartları geçerlidir. Yorumunuz başarılı şekilde gönderildi reCaptcha doğrulanamadı
Muhabbetle ASP.NET Core ile geliştirildi.