O actor model z perspektywy paru miesięcy pracy

Posted on Sun 13 November 2016 in .NET

Cześć. Jako, że od pewnego czasu actor model staje się coraz bardziej popularny w technologii .NET chciałem nieco więcej opowiedzieć o pracy z takim rozwiązaniem. W pierwszym poście chciałem wprowadzić nieco moich przemyśleń i teorii bez kodu. Gdyby zdarzyło się tak, iż, jeszcze nie wiesz co to jest actor model to na początek może nieco przedstawię skąd to się wzięło. Cała architektura actor model opiera się (na co wskazuje sama nazwa) na aktorach. W wielkim skrócie każdy, aktor jest jakby osobnym wątkiem, natomiast sam w sobie jest jednowątkowy. Poszczególni aktorzy komunikują się ze sobą za pomocą komunikatów, jeżeli dany komunikat dotrze do aktora jest odkładany do skrzynki odbiorczej adresata, po czym jeżeli aktor nie ma co robić, a w skrzynce znajdują się komunikaty to bierze kolejny i przetwarza. Sam pomysł na takie podejście nie jest czymś nowym, bo pojawił się już dawno jako część funkcyjnego języka Erlang i nie zdobył on specjalnego uznania. Obecnie ta koncepcja powraca z paru powodów: po pierwsze, tworzymy coraz większy software, który musi być skalowany, zarówno w kontekście chmury jak i procesorów multicore; po drugie, coraz większa popularyzacja DDD oraz CQRS/ES do implementacji, których actor model wydaje się wprost stworzony; po trzecie modne ostatnio podejście Rx. Co do technologii, które oferują takie podejście actor model, to jest ich kilka i istnieją implementacje nawet do języka C/C++. Ze względu na zawodowe doświadczenie w dalszych artykułach będę pokazywał bibliotekę Akka.NET, która jest w linii prostej portem identycznego rozwiązania ze świata Scali(JVM). W samym .NET istnieje jeszcze implementacja MS czyli Orleans, ale nie będę o niej się wypowiadał ze względu na brak wiedzy. Do czego więc cały taki actor model się nadaje. Według mnie oraz moich doświadczeń to actor model nadaje się do :

  • DDD
  • CQRS/ES
  • Analiza/Wyszukiwanie dużych zbiorów danych
  • Elementy serwerowe dla gier komputerowych
  • Systemy obliczeniowe oparte na wielowątkowości

Pewnie znalazłoby się jeszcze coś, ponieważ im bardziej zapoznaje się z tym rozwiązaniem tym więcej widzę jego zastosowań. Jedyne do czego nie polecam actor modelu to aplikacje CRUD’owe. W przypadku gdy twój system jest tylko nakładką na bazę danych i nie ma w nim żadnych procesów biznesowych to ubranie go w actor system może go tylko niepotrzebnie skomplikować, bez dodatkowych benefitów. Załóżmy jednak, że twój system obsługuje jakieś procesy biznesowe, a do tej pory jest CRUD’em lub co gorsza spaghetti systemem, to jak najbardziej warto zainteresować się actor modelem. Aby praca z takim rozwiązaniem nie była drogą przez mękę na samym początku należy zapoznać się z pewnymi koncepcjami, które nieco usprawnią pracę, a mianowicie:

  • niezmienność (immutability) - bardzo często w naszych aplikacjach posiadamy tzw. stan współdzielony. Jest on realizowany na wiele sposobów np. singleton czy zmienne globalne. Zakładając, iż actor model jest wielowątkowy to co do niego wysyłamy musi być niezmienne, ponieważ współdzielony zmienny stan jest wrogiem jakiejkolwiek wielowątkowości.
  • grafy - jest to nieco zbyt uogólnione, ale aktor model można przedstawić w postaci drzewa, gdzie mamy główne miejsce dostępowe, natomiast poszczególne elementy przetwarzania są w nim rozmieszone coraz głębiej i nie są dostępne z zewnątrz.
  • asynchroniczność odpowiedzi - w normalnych systemach flow można opisać w następujący sposób: mamy jakiś widok, gdzie klikając wywołujemy jakieś akcje, jest ona obsłużona przez jakiś serwis “domenowy” a jej rezultat jest widoczny właściwie od razu. W przypadku actor modelu i podejścia wielowątkowego musimy reagować na odpowiedź, kiedy ona przyjdzie i nie oczekiwać, iż zostanie ona zwrócona od razu. Rozważmy następującą sytuację mamy aktora A, który przekazuje wiadomości do aktora B. B z kolei tworzy n dzieci te wykonują właściwe zadanie a kiedy ostatni z nich zakończy wykonywanie to zwraca jest dopiero ostateczna odpowiedź. Takie przetwarzanie może zająć sporo czasu, więc nie blokujmy UI tylko pozwólmy użytkownikowi działać dalej, a gdy przyjdzie odpowiedź poinformujemy go o tym.

Pewnie elementów mógłbym wymienić więcej, ale wydaje mi się, że powyższe sprawy są kluczowe. Co do moich odczuć po paru miesiącach pracy z rozwiązaniem opartym o actor model to mam parę przemyśleń. Po pierwsze czasem implementując funkcjonalność ciężko jest oddzielić framework actor modelu od implementowanej funkcjonalności. Nie chodzi mi tu o to, że sama biblioteka jest niemożliwa do oddzielenia, ale podczas implementacji miałem sporo momentów, kiedy jakąś logikę zaimplementowałem w samych aktorach. Po drugie każdy komunikat to osobna klasa. I tak ma to sens, ale w momencie kiedy mamy komunikatów sporo musimy mieć sporo plików, ponieważ nie wrzucimy 100 klas do jednego pliku. Z czasem kiedy projekt zaczyna rosnąć, nawigacja i ogarnięcie co gdzie jest zaczyna być problematyczne. Mimo tych problemów polecam zainteresowanie się tematem actor modelu, ponieważ może on pomóc Wam w budowaniu dużych i skalowalnych systemów.