Akka oraz Typesafe Activator podstawy część 1

Zawsze nadchodzi taki moment, gdy musimy zacząć pisać wydajnie. Wielowątkowo. Jeśli ktoś próbował kiedyś pisać własny kod oparty na wątkach, to wie, że nie jest to prosta sprawa. Kod robi się bardzo zagmatwany, trudny w utrzymaniu, mało czytelny.

Czy nikt nie wymyślił czegoś … prostszego? Fajniejszego? Okazuje się, że można pisać wydajne aplikacje wielowątkowe, które będą proste w utrzymaniu, szybkie w działaniu, i nie musimy spędzać nad tym za dużo czasu.

Mi się podoba Akka od Typesafe – akka.io

Akka tak samo jak wszystkie rozwiązania firmy Typesafe (o której napiszę w kolejnych blogach) wspiera tzw Reactive Manifesto. Polecam sobie przeczytać o co w tym chodzi, jest to wg mnie przyszłość pisania aplikacji.

W telegraficznym skrócie chodzi o to, aby pisać aplikacje które będą:

  • Reactive – nawet nie wiem jak to przetłumaczyć na nasz język 🙂 Chodzi o to, aby czas odpowiedzi był jak najkrótszy.
  • Resilient – system ma działać i odpowiadać w odpowiednim czasie nawet gdy pojawią się błędy.
  • Elastic – system ma być „elastyczny”, ma się sam dostosowywać do aktualnego obciążenia, działać w każdych warunkach i odpowiednio zarządzać zasobami.
  • Message driven – to jest najciekawsze – system ma działać na podstawie przesyłanych wiadomości, które są wykonywane asynchronicznie.

Taki ładny rysunek jest na stronie akka.

 

Akka – aktorzy – Aktorzy to tak na prawdę wątki, które wykonują jakieś zadania, na podstawie poleceń (messages), jakie im wydajemy. Z punktu widzenia akka nie ma znaczenia, czy aktor znajduje się na tej samej maszynie, czy na innej, system aktorów potrafi działać w systemach rozproszonych.

Przekazujemy wiadomość (message) od aktora do aktora, wiadomości zawierają dane, aktorzy je wykonują i „rozmawiają” ze sobą za pomocą wiadomości.

Proste? Okazuje się, że bardzo proste 🙂

Jak zacząć zabawę z akka? 

Typesafe daje własną platformę, która oparta jest na SBT. Nazywa się TypeSafe Activator – https://typesafe.com/community/core-tools/activator-and-sbt

Sciągamy najnowszą paczkę i rozpakowujemy.

Typesafe Activator ma w sobie dwa „tryby” – tekstowy oraz graficzny. Na początek dla poznania jego możliwości warto użyć trybu graficznego. Odpalamy go poprzez wpisanie w konsoli:

activator zacznie sciągać paczki jakie są mu potrzebne do pracy, ewentualnie się zaktualizuje i po chwili odpali się przeglądarka z gui activatora.

Za jego pomocą możemy stworzyć nowy projekt używając gotowych templatek – małych projektów z samplami jak szybko zacząć pisać w danej technologii…

Ja na potrzebę tego tutoriala użyłem template: „Hello Akka!”

Po sciągnięciu projektu uruchamiamy go poprzez wpisanie w konsoli:

activator udostępnie linie poleceń SBT. Na temat SBT napiszę kiedyś osobny wpis 😉

na tą chwilę kilka przydatnych poleceń:

  • run – odpala aplikację 🙂
  • gen-idea lub idea – generuje projekt dla IntelliJ
  • eclipse – generuje projekt dla Eclipse

do idea/eclipse możemy dodać parametr – with-source=true – wtedy activator ściągnie nam dodatkowo wszystkie źródła, przydatne w developemencie.

Uwaga – jeżeli posiadamy najnowszego IntelliJ to IntelliJ sam sobie znajdzie projekt SBT i dokona odpowiednich importów. Nie musimy generować projektów 🙂

Kilka słów o samym projekcie SBT – SBT to taki builder projektów głównie dla Scali, ale działa również bardzo dobrze z Javą.

Najważniejszy plik to build.sbt – to taki trochę odpowiednim pom.xml dla maven. Definiujemy w nim zależności aplikacji, biblioteki, tryby uruchomieniowe, wszystko co jest potrzebne. Biblioteki – możemy używać praktycznie dowolnych bibliotek maven’a, sbt dobrze sobie z nimi radzi, jedynie musimy je odpowiednio importować (jeśli szukamy pakietu poprzez mvnrepository.com to przy wyborze pakietu mamy zawsze linijki co wpisać, wybieramy sekcję sbt i wpisujemy do build.sbt w dependency to co chcemy 🙂

Dobra, dość gadania o niczym… show me the code… 🙂

W templatce mamy już przykładowy kod, opiszę go trochę w tym wpisie, a w kolejnym, napiszę coś sam 🙂

Cała aplikacja to tak na prawdę jeden plik

ok… WTF? Jak się za to zabrać…

w 42linijce mamy naszego maina… zobaczmy co on robi.. .

Pierwsze i najważniejsze – musimy włączyć system aktorów, robi się to banalnie 🙂

od teraz mamy już główny system aktorów. Póki co nie ma ich, ale mamy już zainicjowaną „główną szynę danych”, po której będziemy gadali z aktorami…

To teraz czas na stworzenie aktora…

to dość zagmatwane… spójrzmy na klasę Greeter:

Hmm… ok.. czyli wiemy już sporo…

Aktor musi rozszerzać UntypedActor (może też inne, ale o tym w kolejnym wpisie 😀 )

Każdy aktor MUSI implementować jedną metodę: onReceive(Object message)

Metoda ta zostanie wykonana gdy aktor dostanie wiadomość (message). Jak widać wiadomość musi byc obiektem. Praktycznie jakimkolwiek 🙂

I całe zadanie aktora, to jest wykonanie jakiejś operacji na podstawie tej wiadomości… Proste prawda? 🙂 To jest cała zasada pracy aktorów… dostać wiadomość, i coś z nią zrobić… I potem czekać na kolejną wiadomość…

UntypedActor udostępnia kilka ważnych metod, które opiszę dokładniej w kolejnych tutorialach… jedna z metod to getSender() – metoda ta zwraca nam AKTORA, który wysłał nam wiadomość… Tak.. to taki trick, aktor jest odizolowany od zwyklego systemu javy, nie ma kontekstu w jakim jest uruchomiony, wie jedynie to, od kogo dostał wiadomość. i metoda getSender() udostępnia mu tego aktora… i może on coś mu powiedzieć… czyli przekazać wiadomość ! zauważcie, że metoda onReceive jest typu void, więc aktor sam z siebie nic nie zwraca, wynik ewentualnej operacji może przekazać jedynie za pomocą powiedzenia czegoś innemu aktorowi… Bardzo to upraszcza kod i sprawia, że wszystko jest asynchronicznie i nie blokujące! mówimy coś aktorowi, i nie czekamy na odpowiedź… Jeśli będzie trzeba, to aktor nam odpowie jak wykona pracę.

Jeśli uważnie czytaliście to co napisałem, to rodzi się pytanie… jeśli mamy przekazać coś aktorowi, a sami nie jesteśmy aktorami?
Możemy to zrobić na dwa sposoby:

  • użyć „aktora” noSender 🙂 – to taki specjalny aktor, który informuje aktora, że żaden aktor mu nie wysłał wiadomości… tak jakby nie było nadawcy (dokładniej – jest nadawca, ale nikt nie odbierze wiadomości, jeśli aktor ją wyśle)
  • stworzyć własny inbox.

Co to jest inbox?
Każdy aktor ma swoją skrzynkę odbiorczą. Skrzynka odbiorcza, to stos, na którym leża wiadomości przesłane do tego aktora. Czyli gdy wiadomość dotrze do aktora, ląduje ona w jego inbox’e, i jeśli aktor akurat nic nie robi, wiadomość idzie do metody onReceive. Dzięki temu możemy aktorowi wysłać milion wiadomości, i będzie on je przetwarzał po kolei (możemy oczywiście na to wpływać, ale to nie w tym wpisie 😉 )

Tyle teori.. a teraz praktyka..

wróćmy do metody main …

tak właśnie tworzymy inbox… czyli naszą skrzynkę z wiadomościami. Nie jest ona przypięta do aktora, jest nasza w kontekście zwykłej aplikacji Java.

Tak właśnie przekazujemy wiadomość do aktora… greeter to aktor którego zainicjowaliśmy… tell to metoda, WhtoToGreet to obiekt przekazany jako message… a ActorRef.noSender() to informacja, że nikt nie ma wysyłającego… I teraz możemy sobie zobaczyć jaki będzie efekt? Patrząc na kod aktora Greeter, jest sprawdzenie, czy wiadomość jest instancją klasy WhoToGreet .. i jest podejmowana jakaś akcja… ustawienie Stringa… Proste 😉

Teraz użycie Inbox’a

wysłanie wiadomości za pomocą inboxa… parametry podobne… greeter to aktor, new Greet() to wiadomośc…

i co wtedy greeter robi?

popatrzmy w kod klasy Greeter:

czyli pobieramy sendera (nasz inbox!), i przekazujemy mu nową wiadomość 🙂 getSelf() to metoda, która przesyła informację o tym że my(jako aktor Greeter) wysłaliśmy wiadomość. Chyba też proste…

Teraz jak się dobrać do Inbox’a?
Tutaj nie ma prostej sprawy. Pamiętajmy, że aktorzy działają asynchronicznie, i nie mamy jawnej informacji, kiedy nadejdzie wiadomość… w tutorialu założono, że odpowiedź nadejdzie po 5 sekundach…

Na potrzeby tutoriala oczywiście wystarczy 🙂 Prosta sprawa. odpytujemy inbox o nową wiadomość, czekamy max 5s na odbiór wiadomości…

Pozostały kod jest podobny i myślę, że nie potrzeba go komentować, poza jeszcze jedną konstrukcją:

to jest piękna sprawa 🙂
Możemy sobie utworzyć aktora, który będzie wykonywał jakieś zadanie co określony czas. Do tego służy scheduler…
krótki opis parametrów schedulera…

  • initial delay – opóźnienie z jakim wystartuje aktor
  • interval – co jaki czas ma być startowany
  • receiver – kto ma otrzymać – tutaj może być albo aktor, albo cokolwiek co implementuje Runnable… czyli czasem nie musi to być aktor ! Fajne 🙂
  • message – wiadomość
  • execution context – dispatcher – tego nie opiszę tutaj, póki co po prostu system.dispatcher()
  • jeśli receiver jest aktorem, to musimy podać kto jest senderem

W powyższym przypadku zauważcie, że senderem jest aktor, który de-facto nie wysłał wiadomości, może to być dowolny zarejestrowany aktor 😉 Taki trick.

 

Mam nadzieję, że tym wpisem zainteresowałem Was trochę systemem aktorów. Dają one bardzo duże możliwości i poprzez wykonania kodu asynchronicznie, na pewno usprawniają działanie aplikacji.

W kolejnym wpisie napiszę jakiś kod z użyciem aktorów, pokażę jak ich używać w Java 8, i jak wyciągnąć z nich dużo więcej 🙂