Akka.Net, Actor Model, .Net Dünyasında Dağıtık Programlamanın Geleceği ve Mikroservisler

Deniz İrgin
Codefiction
Published in
13 min readAug 27, 2017

Merhaba,

Öncelikle giriş yazısını yazarken en çok zorlandığım ve üzerinde düşündüğüm yazılardan biri olduğunu belirtmek istiyorum. Uzun süredir Actor Model ve implementasyonlarından biri olan Akka.Net üzerinde çalışıyorum. Özellikle bir programlama modeli olarak Actor Model, benim yazılımda favori yaklaşımlarımdan biri haline geldi. Sonda söyleceğimi başta söyleyeceğim. “Actor Model ile ne yapabilriz?” sorusuna vereceğim cevap “Herşeyi!” olacaktır. Biraz abartı gelebilir ama yazının ilerleyen bölümlerinde sizi ikna edeceğimi ve Actor Model tarikatına katacağımı düşünüyorum :)

Actor Model, 1973 yılında Carl Hewitt tarafından tasarlanmış, belli prensipler üzerine kurulmuş bir Concurrency modeli. İlk olarak kendisinin yayınladığı “A Universal Modular ACTOR Formalism for Artificial Intelligence” makalesinde adı geçiyor. Ticari anlamda ilk defa Ericsson tarafından Erlang dili tasarlanırken kullanılıyor. Actor Model ve OOP (Object Oriented Programming) arasında kavramsal olarak belli benzerlikler olması tesadüf değil. Carl Hewitt, Actor Modeli geliştirirken, OOP’un öncülerinden Alan Kay’in Smalltalk dilinin “Herşey bir nesnedir ve nesneler birbirleriyle sadece mesajlar göndererek haberleşirler” prensibinden etkileniyor. Zaten Actor Model’de de herşey bir Actor ve Actor’ler birbirlerine belli mesajlar göndererek haberleşiyor :)

Peki Neyi Çözüyor Actor Model?

Eski günlerde biz yazılımcılar, yazdığımız uygulamaların daha hızlı çalışması için daha hızlı CPU’ların çıkmasını bekliyorduk. Ancak uzun bir süredir biliyoruz ki işlemciler daha fazla hızlanmıyorlar, mevcut teknolojiyle işlemcilerin hız limitine ulaşıldı. O yüzden işlemci üreten firmalar artık işlemcilerine daha fazla çekirdek koyuyorlar.

Haliyle biz yazılımcılar artık uygulamalarımızı daha hızlı çalıştırmak istiyorsak, birden fazla çekirdekle verimli çalışacak şekilde tasarımlar yapmamız gerekiyor. Yani Concurrency’i (eşzamanlılığı) kucaklamamız gerekiyor. Multi-thread uygulama geliştirmiş arkadaşlarımız bu sürecin ne kadar zorlu ve acılı olduğunu bilirler.

Object Oriented diller Concurrent işler yapmak için maalesef ideal bir çözüm önermiyorlar. Yıllardır kullanılan thread’ler ise ideal olmaktan çok uzaklar. Multi-thread uygulamalarda geliştirme yapılırken çok dikkatli olunması gerekiyor, canlı sistemlerde çıkan bug’ları bulmak, trace etmek çok zor, bu yolda helak olan bir sürü developer var.

Mutable Shared State

Object Oriented dillerde herşeyin bir nesne olduğunu biliyoruz. Her nesnenin memory’de kapladığı bir alan var, her nesne kendi içerisinde state tutuyor. Tek thread uygulamalarımızda herhangi bir problem yok. Ama işin içine birden fazla thread girdiği zaman işler karışıyor. Bir nesnenin instance’ında birden fazla thread’in aynı anda işlem yapması yönünde bir engel yok. Yani bir nesne’nin state’ini birden fazla thread değiştirebilir. Böyle durumlarda Race Condition dediğimiz sorunlar oluşabiliyor. Bunun için lock mekanizmaları var. Lock kullanarak shared data’ya aynı anda sadece bir thread’in girmesi gibi kısıtlar koyabiliyoruz ama bunun dikkatsiz kullanımında multi-thread’in avantajlarından yararlanamıyoruz çünkü bu durumda da thread’ler birbirlerini bekliyorlar.

Bazen dead-lock’lar da oluşabiliyor, Thread A işini bitirmek için lock’lanmış olan bir resource’daki Thread B’nin işini bitirmesini bekliyor ama kader ağlarını örmüş bikere, Thread B’de işini bitirebilmesi için Thread A’nın lock’ladığı resource’a ulaşması lazım.

Bu tip sorunların özellikle canlı sistemlerde takip edilip, çözülmesi çok zor. Elbetteki onlarca yıl içerisinde bu sorunlar çözülmüş ve belli best-practice’ler oluşmuş durumda ama bunları uygulamak hem maliyetli hem de yer yer kodun bakım yapılabilirliğini düşüren şeyler.

İşte Actor Model tam bu noktada imdadımıza yetişiyor. Actor Model bize concurrent (eşzamanlı) ve distributed (dağıtık) bir uygulama geliştirirken, higher level of abstraction (yüksek düzeyde soyutlama) sağlıyor. Yani tek thread’li yapının konforunu sağlarken aynı zamanda multi-thread bir yapının gücünü ve performansını sağlıyor.

Actor Model

Actor Modeli anlamak için Actor’ün ne olduğunu anlamamız gerekiyor. Actor Modelin kalbinde haliyle Actor var. Bu noktada Actor’ü anlatırken Carl Hewitt’in notlarından yararlanacağım. Sonrasında Actor nedir, ne yapar daha detaylı bir şekilde anlatmaya çalışıcağım.

Actor

Actor en temel hesaplama (computation) birimidir. Sadece bir concurreny biçimi değil aynı zamanda bir hesaplama modelidir. Bir actor üç temel görevi yerine getirir ;

  • Processing (Bilgi işleme)
  • Storage (Saklama, Kaydetme)
  • Communication (İletişim)

Bir Actor Model’de herşey bir Actor’dür. Actor’lerin kendi memory’leri vardır. Actor’ler asenktron bir şekilde, birbirleriyle immutable (değiştirelmez) mesajlarla haberleşirler.

Yukarıdaki cümlelerdeki Actor’leri Nesne kelimesiyle değiştirirseniz aslında OOP’un tanımına yakın bir tanım yapmış oluyorsunuz. Ama buradaki en büyük fark asenkron olması ve immutable olması. Bir Actor sisteminde dolaşan mesajlar mutlaka immutable olmalıdır. Bununla ilgili detaylı bilgiyi yazının ilerleyen bölümlerinde vereceğim.

Actor Sistemin bize sağladı en büyük avantaj aslında bir sistem içerisinde Actor’lerin birbirlerinden izole bir şekilde çalışmalarıdır, birbirlerinin state’lerini ulaşamazlar, değiştiremezler. State’lerini birbirlerine gönderdikleri immutable mesajlarla paylaşırlar, değiştireceklerse de ancak bu immutable mesajlarla değiştirebilirler. Hatta bir actor kendi state’ini bile kendisine mesaj göndererek değiştirir. Bir Actor aynı anda sadece bir mesaj işler yani bir actor’ün içerisinde aynı anda sadece bir thread vardır. Dolayısla Actor’ün state’inin aynı anda birden fazla thread’in değiştirmesine imkan yoktur. Actor state’ini işlediği mevcut mesajla değiştirir ve bir sonraki mesaj bu yeni state’e göre işlem yapar. Actor’ler aslında aynı zamanda bir State Machine’dir.

Peki Actor’ler ne yapabilirler?

  • Kendilerine gelen mesajları işlerler.
  • Başka Actor’lere mesaj gönderebilirler.
  • Başka Actor’ler yaratabilirler.
  • Mesajlar arası davranışlarını (Behavior) değiştirebilirler.
  • State tutarlar.

Yukarıdaki animasyonu daha önce yaptığım bir sunumdan aldım. Job Coordinator Actor’ün başlangıç state’i yeni bir iş bekleme durumunda. Bu Actor’ün kendisine gelen iş başlatma isteklerini, yani tehlikeli işleri harcanabilir başka actor’lere delege ettiğini ve aynı anda sadece bir işin çalıştırılmasından sorumlu olduğunu düşünelim. Actor Modelde bu tip tehlikeli (Database, tcp connection, io işlemleri vb.) işleri Parent Actor’lerin Child Actor’lere devretmesi oldukça yaygın bir pratiktir, böylece bir exception durumunda sadece child actor bu durumdan etkilenir, bu konuyu Fault Tolarance kısmında detaylıca anlatacağım.

Job Coorinator Actor kendisine gelen Start Job mesajından sonra, işi delege edeceği Worker Actor’ü yaratıyor ve Processing durumuna geçiyor, bu noktadan sonra yeni gelen yeni Start Job mesajları bir sıraya alınıyor ve işlenmek için sırada bekletiyor. Yani Job Coordinator Actor kendi davranışını (Behavior) değiştiriyor ve başlangıç durumundan farklı bir davranış sergiliyor. Worker Actor işini bitirip sonucu döndükten sonra tekrar eski davranışına dönüyor ve sıradaki mesajı işliyor.

Bu sistemden aynı andan sadece bir iş çalışması kısıtını kaldırıp da çalıştırabilirdik. Yani Parent Actor kendisine gelen her yeni iş mesaj için yeni bir Child Actor yaratabilirdi. Bu pattern’e de Child-Per-Entity pattern’i deniliyor. Parent Actor kendisine gelen onbinlerce iş başlatma mesajı için onbinlerce child actor yaratabilirdi ve bu child actor’ler hiç bir şekilde birbirlerini etkilemeden işlerini bitirip, sonuçlarını parent’ına gönderebilirlerdi. Ve bütün bu işlemler asenktron olarak gerçekleşirdi ve hatta child actor’ler gerekiyorsa kendi child’larını da yaratabilirlerdi.

Yani Actor’ler bize ;

  • Aynı anda sadece bir mesaj işlemeyi
  • Mesajları FIFO olarak işlemeyi
  • State’lerine kimsenin ulaşmamasını

Garanti ediyorlar. Bunu da bir inbox yapısıyla sağlıyorlar.

Actor Sistemini kullanan uygulamalar doğası gerekeği düşük memory izi bırakırlar. Çünkü geleneksel mimarilerin aksini birbirini çağıran 10'larca method yoktur, yani stack trace çok küçüktür, birbirleriyle mesajlar aracılığıyla haberleşirler. Örneğin Actor Model’i implemente eden sistemlerden biri ve bu yazınında konusu olan Akka’nın tek bir makinada saniyede 50 milyon mesajı işleyebildiği ve 2,5 milyon actor’ün memory’de sadece 1 GB’lık bir alan tuttuğu söylenmektedir.

Akka.Net

Actor Model’in çeşitli platformlarda çeşitli farklı implementasyonları var. Sırf .Net dünyasında bile birden fazla framework mevcut. Örneğin Microsoft’un Orleans projesi bunlardan biri. HALO 4'ün bütün online sevisleri Orleans üzerine kurulu. Aynı şekilde Microsoft’un Azure platformunda sağladığı Service Fabric yapısı Actor Model üzerine kurulu ve oldukça güçlü bir Mikroservis alt yapısı sağlıyor.

Ama ben bugün JVM Scala dünyasındaki Akka’nın .Net’e port edilmiş hali Akka.Net projesinden bahsedeceğim.

Akka.Net, Akka ile karşılaştırılınca nispeten yeni bir proje, ilk release’i 2014 yılının ortalarında. Fakat geçen haftalarda bu yazıyı da yazmama vesile olan v1.3.0 versiyonunu duyurdular. Bu versiyonla beraber Akka.Net projesini .Net Standard’a çevirdiler. Böylelikle Akka.Net .Net Core’da çalışabilir hale geldi, ayrıca bu sürümüyle beraber .Net Foundation’a da girmiş oldu. Şuan Akka.Net kullanarak Xamarian dahil birçok platform’da uygulama geliştirebilirsiniz, yakın zamanda da Unity3d ile de beraber çalışacağı duyruldu.

Çalıştığım firma Akka.Net’in early adopter’larından sayılabilir. Bazı kütüphanelerini daha beta’dayken kullanmaya başladık ve biraz da heycanla daldığımızdan tedbirsiz davrandık ve sonucunda uykusuz gecelerimiz oldu :) Şuan üzerine kurduğumuz sistem stabil olarak çalışıyor olsa da size tavsiyem bir projeye girişmeden iyi öğrenmeniz ve best practice’lerini mutlaka uygulamanız yönünde olacaktır. Bazen developer’lar olarak karşımıza bizi heycanlandıran teknolojiler çıktığında bu prensibi unutabiliyoruz.

Peki Akka.Net Bize Neyi Sağlıyor?

Akka.Net Actor Model’in prensiplerini implemente etmiş bir framework. Ama en büyük gücü Local bir ortamda tasarladığınız Actor Sisteminizi, çok ufak bir konfigurasyon değişikliğiyle yüzlerce makinada koşan distributed bir sisteme taşımanıza imkan sağlıyor olması. Çok güçlü bir Cluster yapısı var. Bütün sistem Location Transparency (Konum Şeffaflığı) üzerine kurgulandığı için Actor’lerinizin Local’de mi yoksa Berlin’de bir makinada mı çalıştığının bir önemi yok. Actor’ler de birbirlerine mesaj gönderirken aslında hangi Actor’ün nerede olduğunu bilmiyorlar ve umarsamıyorlar.

Akka.Net ile kolayca Concurrent ve Distributed mimariler tasarlayabilirisiniz. Elastic ve dağıtıktır, kolayca Scale (ölçeklendirme) edebilirsiniz. Yüksek Performanslıdır, yukarıda da bahsettiğim gibi tek bir makinada saniyede 50 milyon mesajı işleyebildiği ve 2,5 milyon actor’ün memory de sadece 1 GB’lık bir alan tuttuğu söylenmektedir. Framework oldukça genişletilebilir şekilde yazılmıştır, her parçasını değiştirmeniz ve genişletmeniz mümkündür. Resilient (Dayanıklı) olarak tasarlanmıştır, gerçekten doğru tasarladığınızda 7/24 sorunsuz çalışan hata toleransı yüksek, kendi kendi iyileştirebilen bir sistem tasarlamanız mümkün. Ayrıca Open-Source bir proje. Projeyi en başlarından beri takip ediyorum ve her release’de büyük bir community desteği ile hareket ettiklerini söyleyebilirim. İsteyen herkes katkıda bulunabiliyor. Ayrıca Akka.Net’in doğal olarak Reactive olduğunu da belirteyim.

Biraz daha derinlemesine dalmadan önce Akka.Net’in modüllerinden bahsetmek istiyorum. Akka Core Library’si haricinde altı tane ayrı kütüphanesi daha var. Cluster’lı bir yapı tasarlamayacaksanız, Actor’leriniz sadece tek process’de çalışmasını istiyorsanız Core Kütüphaneyi kullanmananız yeterli. Ama daha önce bahsettiğim gibi ufak bir konfigurasyon değişikliği ile dağıtık bir yapıya geçmeniz mümkün.

Akka.Remote

Actor’lerinizi başka makinalara deploy etmenizi ve aralarındaki TCP/IP bağlantını sağlayan temel kütüphane bu. Tek başına da kullanabiliyor fakat genelde Akka.Cluster ile beraber kullanılıyor.

Akka.Cluster

Bir cluster sistemini oluşturmanızı bunu elastic hale getirmenizi sağlayan ve scalabilty gibi konuları çözen kütüphane bu. Akka.Remote üzerine çıkılmış ekstra bir katman olarak düşünebilirsiniz. Ama Akka.Remote’a göre çok daha yetenekli bir kütüphane.

Akka.Cluster.Tools

Cluster Singleton, Distributed Pub-Sub gibi pattern’leri uygulmanızı kolaylaştıran yardımcı bir kütüphane.

Akka.Cluster.Sharding

Cluster’larınızı Shard’lara bölmenize imkan veren veya birden fazla farklı Cluster’ın birbiriyle haberleşmesini sağlayan kütüphane.

Akka.Persistance

En yoğun kullanılan kütüphanelerden biri Akka.Persistance. Size özel tipte bir Actor veriyor. Bu Actor çeşitli durumlarda kendi State’ini persist edebiliyor ve kendini tekrar recover edebiliyor. Bu kütüphane üzerine çıkılmış ondan fazla farklı SQL ve NO-SQL veritabanını kullanmanıza imkan sağlayan farklı kütüphane de mevcut.

Akka.Streams

Actor’leri ve iş akışlarını (work flows), event ve mesaj stream’lerine (akışlarına) dahil etmenize izin veren, Domain-Specific Language (DSL) içeren çok güçlü bir kütüphane. Ve popüleritesi Akka dünyasında giderek artıyor.

Bir Actor’ün Anatomisi

Yazıyı buraya kadar okudaysanız bir Actor’ün aşağa yukarı ne yaptığını anladığınızı düşünüyorum. Bir kod örneği göstermek gerekirse ;

https://gist.github.com/Blind-Striker/b9f8b5d4dd6a1dfec8b59c0f32623430

Yukarıdaki örneği Login olan kullanıcların, izlediği filmleri kaydeden ve bu veriler ışığında kendisine film önerisinde bulunan bir Actor Sisteminden aldım. Bu uygulamanın Demo’sunu bir Codefiction Meetup’ında yapmıştım, ilgili linkleri aşağıya paylaşacağım.

İlk gözüne çarpan Constructor içerisindeki Receive ifadeleri olmuştur sanırım. Bir Actor’ün hangi tipte mesajları handle etmesi gerektiğini Receive kullanarak belirtiyoruz. İlk tanımlama LoginMessage üzerine. Bu Receive tanımlaması, bir login isteği geldiğinde gerekli kontrolleri yaptıktan sonra, kullanıcıya geçmiş verilere göre bir film önerisinde bulunuyor. Bunu da RecommandationActor adında başka bir Actor kullanarak yapıyor.

Diğer Receive tanımlaması ise WatchedVideoEvent adında bir mesajı handle ediyor. Yani izlenen Video’ları tutmaktan sorumlu başka bir WatchedVideoActor var. Buradaki Receive tanımlaması, izlenen video’ları WatchedVideoActor mesaj olarak geçiyor.

Ana Actor’ümüz olan ApiActor yaratıldığında kendisi de RecommandationActor’ü yaratıyor. WatchedVideoActor kendisine constructor’dan parametre olarak geçiliyor. Yalnız dikkat etmeniz gereken RecommandationActor yaratılırken kendisine WatchedVideoActor’ün referansı da geçiliyor. Çünkü film önerisinde bulunması için daha önce izlenmiş filmlerin bilgisine ihtiyacı var. Bu bilgiyi WatchedVideoActor aracılığıyla elde ediyor.

Bu noktada eminim dikkatinizi çekmiştir. Bütün actor’ler IActorRef diye özel bir tipte tutuluyorlar, hiç biri kendi tipiyle ve ya instance’ı ile tutulmuyor. İşte Location Transparency (Konum Şeffaflığı) derken bunu kast ediyordum. Çünkü ApiActor açısından bakıldığı zaman dışarıdan geçilen WatchedVideoActor’ün nerede yaratıldığı, local’de mi yoksa dünyanın öbür ucunda bir makinada mı olduğunun bir önemi yok. Aynı şekilde RecommandationActor’ü yaratan ApiActor, bu Actor’ü local’de mi yoksa remote bir makina da mı yarattığını bilmiyor, bütün bunların hepsi ufak konfigurasyon değişiklikleriyle ayarlanabiliyor.

Receive tanımlarının içerisinde başka Actor’lere mesaj gönderilirken Tell kullanıldığını fark etmişsinizdir. Bu şekilde kullandığınız zaman herhangi bir geri dönüş beklemiyorsunuz ve mesajın işlenmesini bloklamıyorsunuz, mesajı Actor Sistemine havale ediyorsunuz. Mesajı gönderdiğiniz Actor işi bitince size cevap dönebilir veya dönmeyebilir. Burada herşey asenkron olarak gerçekleşiyor. Ama bazı durumlarda Ask kullanmanız gerekebiliyor, böyle durumlarda mesajı gönderdiğiniz Actor’den mutlaka bir cevap beklediğinizi belirtmiş oluyorsunuz, bu tabiki asenktroniteyi biraz kıran ve işi bloklayan bir kullanım ama bazen ihtiyacınız olabiliyor. Belli durumlar haricindeki her durumda Tell kullanmanız tavsiye ediliyor.

https://gist.github.com/Blind-Striker/bff9a13e886af164bd5c7de3e40c089e

Bir Actor’ün hayat döngüsüne çeşitli noktalarda müdehale edebiliyorsunuz. Actor’lerin hayat döngüleri Parent Actor’leri tarafından yönetiliyor. Yani bir exception durumunda ne yapılacağını Child kendi Parent’ına soruyor, bu konuya daha detaylı değineceğim ama bu örnek açısından tek bilmeniz gereken default davranış olarak Parent Actor’un herhangi bir exception durumunda Child Actor’ünü Restart ettiği. Actor’ler bize bu noktalarda araya girip belli işler yapmamıza imkan sağlıyorlar. İlk örnekte gördüğünüz Actor ReceiveActor’den türetilmişti, yukarıdaki örnekte ise UntypedActor kullanıldığını göreceksiniz. Akka.Net’de en temel Actor sınıfı UntypedActor ama genelde mesajları Type-Safe olarak handle etmemize imkan sağladığından dolayı ReceiveActor kullanıyoruz.

Actor Hiyerarşisi

Actor’lerin en temel özelliklerinden birinin başka Actor’ler de yaratabilmesi olduğundan bahsetmiştik. Peki buradaki hiyerarşi nasıl oluyor?

Akka.Net üzerinde iki tane ana Actor var. Bunlardan biri System diğeri User. Bizim tarafımızdan yaratılan her Actor, User’ın child’i olarak yaratılıyor. System’den de anlaşılacağı üzere, bir Actor Sistemi de kendi içerisinde herşeyi yapmak için Actor’ler kullanıyor. Akka.Net de Logging, Serialization, Tcp/ip vb. işler için yine kendi içerisinde Actor’ler kullanıyor.

Her Actor’un bir Actor Sistemi içerisinde benzersiz bir adresi var. Örneğin yukarıdaki şemanın bir local actor sistemi olduğunu düşünürsek en alttaki Actor’ün adresi ;

akka://my-sys/user/a1/b1

şeklinde olacaktı. Burada my-sys olarak geçen yer Actor Sisteminin adını belirtiyor, her Actor Sisteminin mutlaka bir adı olması gerekiyor. Eğer yukarıdaki şemanın local değilde Clustered bir yapı olduğunu düşünseydik en alttki Actor’ün adresi ;

akka.tcp://my-sys@host.example.com:5678/user/a1/b1

şeklinde olacaktı. Gördüğünüz üzere fazladan sadece protokol bilgisi, remote makinanın host adı ve port’u adrese dahil oluyor.

Actor Sistemindeki herhangi bir seviyedeki herhangi bir Actor, adresini bildiği bir Actor’e mesaj gönderebilir. Bunu işlemi de Akka.Net içerisindeki ActorSelection diye özel bir nesneyi kullanarak yapıyoruz. Ama bu tavsiye edilen bir yöntem değil. Çünkü Location Transparency’i özelliğini kullanmamız güçleşebiliyor. IActorRef nesnesi özünde bir metadata ve ulaşmak istediğimiz Actor’e dahil bütün bilgileri barındırıyor ve tamamen serialize edilebilir nesne. Dolayısla Actor’ler arası mesajlaşma da sık sık IActorRef’in de mesaja dahil edildiğini görebilirsiniz. ActorSelection kullanmak yerine tavsiye edilen yöntem, mesajın Sender’ını da yani IActorRef’ide mesaj içine gömmek.

Aşağıdaki şema Actor Hiyeararşisi ve Adres Sistemi hakkında fikir sahibi olmanıza yardımcı olabilir.

Actor Sisteminde Dayanıklılık ve Kendi Kendini İyileştirebilme

İdeal bir dünyada yaşamıyoruz, kurguladığımız sistemler ne kadar mükemmel olursa olsun mutlaka istisnai durumlar yaşanabiliyor. Yani Exception’lar ve Exception’ları handle etmek developer olarak hayatımızın bir gerçeği. Monolith uygulamaların yerlerini yavaş yavaş daha dağıtık yapılara bıraktığı bir dünyaya doğru gidiyoruz. Yani sistemler artık başka sistemlerle iletişim halindeler ve veri alışverişinde bulunuyorlar. Sadece kendi sistemimizde oluşan hataların değil, bizim kontrolümüzde olmayan bir çok sistemde de (Database, başka servisler, io işlemleri vb.) oluşan hataların bizim sistemimizi etkilememesini sağlamamız gerekiyor. Yani yazdığımız uygulamalar çalışmaya devam etmek durumundalar.

Akka.Net ile ilgili en güzel şeylerden biri de kendi içerisinde bir Error Kernel’ı olması. Doğru tasarlanan bir Actor Sistemi aynı zamanda Resilient (Dayanıklı) ve kendi kendini iyileştirebilen (Self Healing ) bir sistem oluyor.

Daha önce pahalı ve riskli işlemerli Child Actor’lere delege etmenin yaygın bir pratik olduğundan bahsetmiştim. Akka.Net’de Parent Actor’lerimize çeşitli policy’ler tanımlayarak, Child Actor’lerde bir hata olması durumunda neler yapılması gerektiğini belirleyebiliyoruz. Buna Supervision Strategy deniliyor. Bir hata durumunda parent actor, child actor’e üç şey yapmasını söyleyebilir. Bunlar Stop, Resume, Restart. Eğer parent actor ne yapması gerektiğini bilmiyorsa hatayı, Escalate ederek hiyerarşideki bir üst Actor’e kararı bırakabilir. Hiç bir Supervision Strategy belirlememişsek, default davranış hata alan child actor’ün yeniden başlatılması olarak uygulanır. Ama biz bunu Exception tipine, hangi Exception’dan kaç saniye içerisinde kaç tane geldiğine göre de özelleştirebiliyoruz. Hatta farklı Exception’lara göre farklı davranışlar da sergilenmesini sağlayabiliriz.

Actor Hiyerarşisinden bahsederken en tepedeki iki Actor olan, User ve System actor’lerinden bahsetmiştim. İşte bunların en tepesinde Root Guardian var. Yani bir Exception’ın en sonunda gidebileceği yer Root Guardian. Ama bu çok nadir yaşanan bir durum. Genelde hatalar User ve ya System Actor’lerinden birinde düzgün bir şekilde handle ediliyor.

İki çeşit Supervision Stratejisi var, bunlar One-For-One Strategy ve All-For-One Strategy. Akka.Net bu stratejiler dışında kendi özel stratejilerinizi de oluşturmanızı imkan sağlıyor.

One-For-One Strategy kullandığınız zaman bir hata durumunda uygulanacak Stop, Resume, Restart gibi aksiyonların direkt olarak hatayı alan Child Actor’e uygulanması sağlanıyor. Bu default strateji çoğunlukla her durumda yeterli oluyor.

All-For-One Strategy ise bir hata durumunda bahsettiğim aksiyonların aynı seviyedeki bütün Child Actor’lere uygulanmasını sağlıyor.

Örnek bir Supervision

Akka.Net ve Mikroservisler

Yazıyı buraya kadar okuyup da hala Akka.Net’in ne kadar muhteşem, harika, hayatımızı kolaylaştıran bir teknoloji olduğuna ikna olmamışsanız ve Actor Model tarikatına üye olmayı düşünmüyorsanız, sizin için oynayacak bir kozum daha var :)

Yazının bir çok yerinde bahsettim. Tasarladığınız Actor Sisteminin local’de çalışmasıyla, dünyanın dört bir köşesinde çeşitli makinalarda çalışması arasında mimari olarak hiç bir fark yok. Yani tasarladığınız mimarileri oldukça kolay bir şekilde distributed hale getirebilirsiniz ve oldukça kolay ölçeklendirebilirsiniz (scalability).

Akka.Net bugün .Net dünyasında Mikroservisleşmek isteyenler açısından en iyi alternatiflerden biri. Çünkü Actor Model’in kendisi de tasarlanırken Distributed Computing için tasarlanmış. Bunların yanı sıra performansı, dayanıklılığı ve kendi kendini iyileştirme konularında da öne çıkıyor.

Özellikle Akka.Cluster bize bu nokta da ihtiyacımız olan bütün alt yapıyı sağlıyor. İncelemenizi tavsiye ederim.

Actor Model Hakkındaki Kişisel Görüşlerim

Öncelikle ben Actor Model kullanarak (Akka.Net’den bağımsız bir şekilde) bir sistemi modellemenin OOP’a göre karşılaştırdığımız çok daha etkili ve doğru sonuçlar vereceğine inanıyorum. Herşey bir nesne’dir demektense herşey bir Actor’dür demek bana daha mantıklı geliyor ve bu yazının en başında da söylediğim gibi bence Actor Model kullanarak herşeyi yapabilirsiniz. Bir Mobil uygulamadan bir Web uygulamasına, bir API’ya herşeyi Actor Model prensiplerini kullanarak tasarlayabilirsiniz. Ve bu yapınızı bir anda distributed yapıya çevirebilirsiniz. Bir API tasarladığınızı düşünün, bir anda çok talep alan kısımların, başka makinelerde çalışmasını sağlayabilirsiniz.

Ama daha önce de dediğim gibi Akka.Net kullanacaksanız derinlemesine öğrenmenizi tavsiye ederim. Çünkü Akka.Net sizi bir Actor Sisteminin en aptal halini veriyor. Bir çok şeyi sizin ön görüp, çözmeniz gerekiyor. Akka.Net’in en büyük gücü ve onu bu kadar hızlı yapan da aslında bu.

Örneğin daha önce de bahsettiğim Microsoft’un Orleans, Akka.Net ile karşılaştırılınca daha limitli ve birçok şeyi kendisi sizin adınıza hallediyor ama Akka.Net ile karşılaştırılınca belli yerlerde 100 kata kadar yavaş kalıyor. Ama öğrenme hızı ve geliştirme kolaylığı açısından Akka.Net’den daha ileride.

Vurgulamak istediğim aslında Akka.Net’den bağımsız bir şekilde, Actor Model’in OOP’dan daha iyi bir sistem olduğu ve Separation of Concerns prensibini uygulamanızı çok daha kolaylaştırdığı.

Actor Model ve Akka.Net konusunda daha önce Mert’le beraber bir Live Coding yaptık. Sonrasında da İkinci Meetup’ımızda konu hakkında bir sunum yaptım. Bu yazıyı da birazcık daha önce yaptıklarımızı tamamlayıcı niteklikte olması için yazdım. Aşağıdaki Linklerden ilgili video’lara ulaşabilirsiniz.

Meetup’da yazdığım örnek uygulamanın kodlarına için ;

https://github.com/CodeFiction/AkkaDotNetCoreDemo

Ayrıca bu yazıyı Akka.Net hakkında bir yazı dizisinin, ilk yazısı olarak da düşünebilirsiniz.

Bir sonraki yazımda görüşünceye dek hepinize iyilikler dilerim.

--

--