Evolution from local application written in Java to actor based one using Akka Actor System. Few examples of how to evaluate simple application in easy way to be scalable and cloud ready. This is show up of almost complete course and workshop of how to build Actor System from scratch.
Actor Model – long history short
Following Hewitt, Bishop, and Steiger’s 1973 publication, Irene Greif developed an operational semantics for the Actor Model as part of her doctoral research.
„Akka” come from goddess in Sami mythology that represented all wisdom and beauty on the world.
Actor is a computational entity that, in response to a message it receives, can concurrently:
- send a finite number of messages to other actors;
- create a finite number of new actors;
- designate the behavior to be used for the next message it receives.
There is no assumed sequence to the above actions and they could be carried out in parallel.
Actor is an entity encapsulating:
Advantages of using Actor Model
- Concurrent application logic
- Async logical operation chain execution
- Schedule once or many times
- Control role based behavior
- Scal-in & Scal-out
- Distribution of work
Like in real life – Events, Domains and Actors
Actor Model can be compared to very real life. Messages are represented by information’s sent by Teacher to Student. However this Student can generate new information’s and make some work. One teacher can control many students. Developing an application based on real life examples is very close to business. That may be a way to achieve Domain Driven Design and Event Driven System.
After this article, see the one that describes Clean Architecture in Software – Simplified Concept and you should understand how easy and quick can be building really enterprise ready applications.
Example of Local Application
In this example there is most easy application that can be developed. You can see that HTTP server is started at 8888 and is serving one endpoint that will generate random number and return it in answer. Moreover that endpoint will convert this number to the word and additionally write it to the in-memory map that has representation of number to word.
After start of this application and making request to
user will see a return representing words like: “one”, “two”, “three” and so on.
To use this as real example just build your project with gradle and run it.
Example local based application will be non async. The only async here that is presented is an async response in grizzly http server that is transparent to developer. Your first application is in one class. You can build it using simple MVC pattern in few classes if you wish.
If so, then you will have some gradle wrapped project, grizzly nio http server with async enabled and controller with local static map.
When ready with this application then can run performance check of it. For this can be used Engulf.
Example results from mine tests
I was able to achieve 2044 requests per second with average response time of 355 ms.
First Actor Model Application using Akka
Concept of roles in actor based application
Lets build the same using Akka and Actor Model. It should be very simple. At the beginning we have to think a little bit and design our system and actors.
In this concept we will use Frontend Actor, Backend Actor and Database Actor.
Let’s split responsibilities and divide them onto actors. Frontend Actor will be responsible for reendering message back to user and accept request from user. Backend Actor will calculate all the stuff. Database Actor will try to write or keep information’s (like database writes / reads). It’s not yet real Event Driven Design or CQRS, but take a look that it may in next steps forward to it. We just are going to be ready.
Let’s start to build akka ready application
To do that you need to:
- add dependencies
- prepare first configuration
- start in code an actor system
I have added in this step all needed dependencies to not bother us later with that.
Simplest config to use in local.
Also from important things, we have to remember to start Actor System.
Start of remote actors that we have defined. Please take a look how Main in application may look like now.
In following class there has been started actors and defined their main properties. Look very carefully to the above code. You should observe, that not only those described at the beginning actors are there. Also a router would be an actor. In example “BackendExecutionActor” is not named “backend”. The router with round robin poll that controls “BackendExecutionActor” is named “backend.
There in Main has been sent first messages to the actors.
Construct actors in local based system
To process messages there have to be present actors. Thiers construction may be very different depending on the needs.
Some of actors need to have parameters during construction. The way of constructing them is a little bit different.
Such an Actor class would accept constructor parameters and use them till end of its lifecycle.
There was present also other type of actors that are not dependent with business logic itself. Those would be threat as infrastructure part.
The rest server will serve his services in one endpoint. During each request to that endpoint there would be created instance of Actor that is responsible for accept request and present answer. There is possibility that taking care of such construction may be delegated to the dispatcher.
Make use of Patterns
There is sometimes need to have blocking code in application. It depends on place where async is meeting with sync. To perform such a connection there are introduced Patterns.
Messages are like Commands and Queries
Answer for a message is done in Actor, just take a look above at Backend Execution Actor.
Work of Actor Model in example
In above first example of Local Actor System has been shown many ways to:
- Construct Actors
- Naming of Actors in a System
- Blocking Patterns
- Way of addressing and sending messages.
After run of Main class from this example, there will be fully working example that uses the same business logic as the very first simple application. It will return in endpoint word that represents a random number.
Checking of performance will show that even if there are many actor created and that simple logs are sent using actor messaging system, it is still very good. It is a way to go fully async in a future.
During short period of checking performance decreased a little bit. We have more inside, it’s natural. However long running will show up that overall performance will increase.
Going into Cluster
Akka Actor System offers a way to easy scale our application. It’s the most important advantage of using this way of programming. Till now there was a running example of akka based backend that is running only locally. However in real situations probably you would need to divide your applications deployments into different servers depend on a role of component.
There are two most important ways to achieve network functionality. First one is Remote and second one is Cluster. Using Remote, there has to be addressing done by hostnames or IP addresses. Using Cluster, Akka offers to take care about infrastructural parts of addressing and offers named based routing. As in most cases there is no need to use Remote, so in example will be used Cluster one.
Divide application into modules and start cluster
Start should be done by dividing existing local application into logical modules. Based on already existing akka backend that is running only in local, we will divide it onto modules:
- Akka Cluster Server
- Frontend (Rest)
Starting of a cluster should be very easy in code.
Akka is using Hockon as a configuration. By default there should be present some config file. We have to assure that our cluster is properly configured.
In Akka there is need to define where is located a server as it offers server – client way of communication. Take care about addressing and main routing gets Receptionist. The Receptionist is an Actor that is offered by Akka itself.
Now it’s part to offer configuration also for logical modules of our application.
There have been used Roles to properly divide application onto the modules. In such a way we may start application components based on configuration defined Roles.
Starting of actor system based on properties may be done by giving name of configuration file.
Register an Actor in Cluster and Route local messages
This part is a most difficult one to understand for persons that are not familiar with server – client architecture pattern. In a short words we can tell that already there was some readable names assigned to actors in previous example and now we have to register them in two places:
- cluster (in receptionist)
Registration in a cluster
Already used names may be used now to guarantee smooth switch from old local akka code to new cluster based code.
In this code there have been created by a Logging Module (so running at this node) an Actor with a name “logger”. With the same name it has been registered in cluster. In such a way a Receptionist that is on module “server” will know where to forward in a cluster messages to the “logger”.
Registering a routing from local name to cluster
As already used code is using a name of actor (like “logger”) to send messages to him, so then there is need in every client that is using such a name to register where it has to be forwarded. For this reason in every client there has to be registered in local an abstract actor with a name “logger” that will get messages in existing client system and forward them to the cluster. A wrapper pattern has been used to do that.
Starting all modules
How to send messages in cluster
Message to One in Cluster
Message to all in cluster
Scalable group of actors in cluster using routing
There are different ways of creating routers and their policies. Take a look that we are sending messages to the router and it’s automaticly forwarding them. Actor instance of Backend Execution Actor is not named “backend” there has been registered a router with that name and such a router will manager of forwarding a message to defined number of Backend Execution Actors instances.
Run an example and check performance
While run the above example on one computer, there can be observed that time of response is lower, however overall performance has decreased. However now scaling is near the linear. Dependent on configurations and number of actor instances, in a quick way you will reach better performance than Local Code Example and will be able to scale almost in linear way. Try it out!
Cluster Example as a Workshop
If you have a second computer available or few ones. If you have a friend available with computer or few friends… then just use existing already Cluster Example. By running this backend on few computers with different roles, you will be able to check performance and see how magic happens and messages are sent between computers in cluster. Just remember to adjust configuration.
Sharding of Data
While now for keep a managing of data we used Data Actor that had infrastructural responsibility to read and write into repository.
Why to not use Actor Model to define the ACTOR as a Data (or Person)?
Let’s imagine that our Word (Number) is also an Actor. In real example it may refer to something like client or device. For sure it may be related with Data pattern called “Aggregates”.
Akka offers Sharding for such a purpose. More about this topic is a part of other posts.
Proxy and Shard with a Guardian and Router
Take a look that in shard it’s easy to manage your data. The actor that is in shard may also send messages to other infrastructural actor that will write snapshot to any database or even use Event Based Architecture.
Modularity in a Sharding as na option in cluster
Location of Actor with Data in a Shard
Message Id Extraction method may be used to decide of where and how to find actor in a shard that keeps data.
Data and it’s distribution
Akka may be a very good way to achieve different patterns including:
- Event Sourcing
- Domain Driven Design
- Clean Architecture in Software
If you look for a method that this part of examples has been written you could observe that transforming was very easy, because from the beginning till the end the code and it’s structure was modular and ready for transformation.
In big systems where there are hundreds of thousands clients, it’s only way to have good performance and avoid bottlenecks.