Arakatmanlar-7. Olay Tabanlı Mimari ve Olay Tasarım Kalıpları

Huseyin Kutluca
Yazılım Mimarileri
5 min readNov 21, 2021

--

Olay Tabanlı Mimari (Event Driven Architecture)

Olay: Bir nesnenin durumunda geçmiş zamanda oluşmuş dikkate değer bir değişiklik olarak tanımlanır. Bir sensörün sıcaklık değişikliğini rapor etmesi, aracın pozisyon ve hız bilgisini güncellemesi, Hisse senedi güncellemesi, E-ticaret sitesinde oluşturulan bir sipariş, siparişin teslim edilmesi örnek olarak verilebilir. Uzak bir noktadaki bir sensörün ölçtüğü olay verisi Uzaktan Ölçüm (Telemetry) olarak ifade edilebilmektedir. Birbiri ile ilişkili olaylar ise genel olarak Akım (Stream) olarak ifade edilmektedir. Bir durumda Uzaktan ölçüm verileri akım olarak nitelendirilebilir. Bunun yanı sıra bir kullanıcının WEB sitesinde yaptığı işlemler serisi, veritabanı değişiklikleri de akım olarak örneklenebilir.

Olay Tabanlı mimari de olaylar oluşturan tarafından yayımlanır, ihtiyacı olan gelip çekmez. Alıcılar olayı aldığında olayı hemen işlerler. Bu olay yayımlandığında onu alan bileşen o olay ile ne yapacağına karar verir. Alan modül cevap dönmek zorunda değildir. Bu mimari kalıp sıralı ve istek, cevap tarzı mimarilere göre daha esnek bir mimaridir.

Olay tabanlı mimari düşünce yapısında değişikliği de gerektirmektedir. Örneğin bir odaya girdiğimizde «Odaya Girildi» olayı yayımlanır. Odada ışıktan sorumlu bileşen odaya girildi olayını aldığında odanın ışığını yakar. Bunun aksi durumda istek tabanlı bir sistem yapsaydık odaya girdiğimde benim «ışığı yak» komutunu ilgili bileşene göndermem gerekirdi. Bu durumda ben odanın durumu ve ne gibi tepkiler verdiğini önceden biliyorum. Olay tabanlı mimaride sorumluğun değişimini dikte eder.

Olay tabanlı mimariler asenkron sistemler oluşmasına katkıda bulunur. Bir istekte bulunup bekleme işlemi olmaz. Olaylar ara katman seviyesinde kuyruğa atılır ve olayı işleyen servisin üzerindeki aşırı yük baskısını azaltır.

Bu mimariler ile bileşenler/servisler birbirine daha az bağımlı olurlar. Servisler arası zamansal, fiziksel ve senkronizasyon bağımlılığı olmaz. Servisler arası ara yüzler belli olunca diğer servislerden bağımsız şekilde geliştirme yapılabilir, servis kendi başına test edilebilir.

Bu mimari ile ölçeklendirme de daha rahat yapılır. Sadece sıkışık olan servis birden fazla çalıştırılarak sistemin çıktı performansı arttırılabilir.

Ayrıca belirli bir servis kapanıp yeniden açıldığında sistem çalışmaya devam edebilir. Kapanıp açılan servis ara katmandan gerekli durum verisini alır ve çalışmaya devam eder.

Olay tabanlı mimari avantajlarının yanı sıra dağıtık yapısından dolayı birtakım zorlukları da beraberinde getirir. Örneğin farklı servislerde aynı olay verisinin farklı versiyonları olabilir. Altyapıdan dolayı aynı olay birden fazla defa iletilebilir ya da olay kaybı olabilir. Klasik atomik işlem (transaction) altyapıda desteklenmez. Bunun yerine sonunda tutarlılık (eventual consistency) yaklaşımı kullanılmak durumunda kalınır. Sonunda tutarlılık yaklaşımında test edilmesi ve hata tespiti daha zor olur. Son olarak servisler arası ara yüzler her ne kadar tasarım aşamasının başında belirlenmeye çalışılsa da proje süresince bu arayüz ihtiyaçtan dolayı çok fazla değişir ve bu değişikliğin yönetilmesi gerekmektedir. Aksi durumda farklı versiyon olay şeması bekleyen servisler bir arada çalıştırıldığında sistemde beklenmeyen durum oluşur. Belkide sadece bir olay şemasında bir veri değişikliği bütün uygulamaların yeniden derlenmesi ve test edilmesini gerektirir.

Olay Tabanlı Sistem Tasarım Kalıpları

Olay Tabanlı veri paylaşımında 3 farklı veri paylaşımı tasarım kalıbı kullanılmaktadır:

  • Olay Tabanlı Durum Paylaşımı (Event Based State Transfer)
  • Olay Bilgilendirme (Event Notification)
  • Olay Kaynağı: (Event Source)

Olay Tabanlı Durum Paylaşımı:

Bu yaklaşımda nesnenin tüm durum bilgisi mesaj içerisinde yayımlanır. Diğer uygulamalar mesajı aldığında en güncel veri olarak bu mesaj içeriği ile işlem yapar. DDS ara katmanı bu yaklaşımı özellikle temel almaktadır.

Bu yaklaşımın avantajı mesaj kendi kendine yeterli olduğundan alan uygulama tarafından işlenmesi kolaydır. Bu yaklaşımda tüm durum verisi uygulamalar arası ara yüzde bulunduğundan veri modeli değişiminden bütün uygulamalar etkilenecektir. Ayrıca her seferinde bütün mesaj iletildiği için bu yaklaşımda paylaşılan verinin boyutu da doğal olarak alternatiflere göre büyük olacaktır.

Olay Bilgilendirme:

Bu son yaklaşımda ise herhangi bir nesnede değişiklik olduğunda nesne ile ilgili sadece anahtar bilgisi ve veya nesneye ait adres bulunmaktadır. Bu yaklaşımda nesne ile ilgili hiçbir bilgi ara katman üzerinden paylaşılmadığından servis ile mesaj birbirinden bağımsızdır. Mesaj içeriği minimaldir ve mesajın gönderilmesi ve işlenmesi son derece kolaydır. Tabi ki bu yaklaşımın getirdiği ek yük veriye ihtiyaç duyan uygulamaların ek bir arayüz üzerinden veriye erişmeleri gerekmesidir.

Olay Kaynağı:

Bu ikinci yaklaşımda veriyi üreten uygulama ilgili nesnede bir değişiklik olduğunda ilgili nesnenin anahtarı ve değişen alanları paylaşacaktır. Bu yaklaşımda daha küçük boyutlu mesajlar iletilmektedir.

Karşı Tasarım Kalıpları

Her tasarım yaklaşımında olduğu gibi tecrübeler ile en iyi kullanım durumları oluştuğu gibi önerilmeyen kullanım durumları da önerilmeyen Tasarım Kalıbı olarak ortaya çıkıyor. Bu kalıplar bunu yaparsanız sisteminizde ara katman kullanmanın avantajlarını yeterince yaşayamazsınız ve hayatınızın kolaylaşmasını beklerken daha da zorlaştığını görürsünüz.

Olaylar arası bağımlılık: Olay tabanlı sistemlerde konular arası ve aynı konudaki iki mesaj arası bağımlılık olmamalıdır. Kullanıcı uygulama bir veriyi aldığında yeni bir mesajı beklemeye gerek duymadan mesajı işleyebilmelidir. Veri içeriği oluşturur iken ihtiyaç duyulacak bütün verinin ilgili veride olmasına dikkat edilmelidir.

Karmaşık Bağımlılık: Servisler arası olayları tasarlarken servisler arası karmaşık bağımlılıkların ve akışların, geri bildirim döngülerinin olmamasına dikkat etmeliyiz. Bu karmaşıklık hem testi olumsuz etkiler hem de gecikmeyi arttırır. Örneğin sisteminize giriş yapan bir olay peş peşe birkaç mesaj akışından fazla akış oluşturuyor ise tasarımınızı gözden geçirmeniz tavsiye edilir. Olay akışı ya da servis bölümlenmesi yeniden tasarlanmalıdır.

Sızıntı Olay: İletilen veriler servisin iç algoritması ile ilgili bilgileri de içermektedir. Bu durumda iç algoritmanın değişmesi diğer uygulamaları da etkileyeceğinden tercih edilmemelidir. İletişim kurulan uygulamalar birbirinin çalışma yöntemlerinden en az şekilde haberdar olmalıdır.

Genel amaçlı mesaj: Konu içerikleri genel amaçlı tasarlanır ve bir konu içinde birden fazla veri gönderilir. Burada ara katmanın birçok özelliği filtrelenmiş olur ve sadece noktadan noktaya veri transferi sağlanır. Bu yöntemin yerine her durum için bir konu ismi ve mesaj içeriği tercih edilmelidir.

Kayıt Tabanlı olaylar: Veritabanı işlemleri olay olarak paylaşılıyor. Bu yaklaşımın sakıncası iç tasarımın diğer modüllere bulaştırılması olarak görülmektedir.

Mesajlar arası bağımlılık : Yine olay tabanlı sistemlerde tercih edilen bir durum değildir. Mesajların diğer uygulamalara erişme sırası farklı olabileceği düşünülerek mesajlar arası bağımlılık oluşturulmamalıdır.

Varsayımsal Bilgi: Olay mesajları kendi başına yeterli olmalıdır. Mesajı gönderen uygulama bunu alan uygulamanın o mesajı nasıl ve ne amaçlı işleyeceği konusunda varsayımı olmamalıdır.

Kılık değiştirmiş komutlar: Birçok olay tabanlı sistem aynı zamanda komutları da ara katman üzerinden göndermeyi tercih eder. Burada her ne kadar noktadan noktaya iletişim olsa da ve komutu gönderen kişi diğer servisin bunu nasıl işleyeceği hakkında bilgisi olsa da bazen bu şekilde de iletişim tercih ediliyor. Bu durumları minimize etmek sistem açısından daha iyi bir tasarım olacaktır.

Metot Çağrısı şeklinde olaylar: Kimi zamanda yayımla abone ol tabanlı ara katman uzaktan metot çağırmaya benzer şekilde kullanılır. Bu durumda uygulamalar arasında çok fazla git gel olacak ve sistemin karmaşıklığı artacaktır.

Altyapı Uyumsuzluğu: MQTT, Kafka, DDS ve AMQP farklı yaklaşımları olan ara katmanlardır. Doğru ara katmanı doğru problem tanımı için kullanmak gerekir. Her ara katmanın güçlü ve zayıf yönleri vardır.

Fazla sayıda Olay: Çok fazla olay oluşturmak ve bunu paylaşmak geliştirilen sistemin karmaşıklığını arttıracaktır. Artan karmaşıklık test, geliştirme ve entegrasyon problemlerine sebep olacağı gibi performans problemleri de yaratabilmektedir.

Olay tabanlı mimarinin her şeyi çözmesini beklemek: Olay tabanlı dağıtık mimariler tabi ki sisteminizi daha yönetilebilir ve modüler yapacaktır. Fakat iyi geliştirme pratikleri, temiz kod yaklaşımı, test otomasyonu, ekip içi iletişim istenilen seviyede değil ise geliştirilen proje başarıya ulaşmaz.

--

--

Huseyin Kutluca
Yazılım Mimarileri

Highly motivated Software Architect with hands-on experience in design and development of mission critical distributed systems.