Exploring Microservices With Play and Akka
Today we're talking about microservices with Play and Akka. This is a fairly well hyped topic about the architecture of software systems, but I don’t want to dive into a discussing the rights and wrongs of the debate on whether microservices are the bee’s knees or just another reincarnation of service oriented architecture, SOA.
Instead, in this first post of a series on microservices I want to look at the qualities that make microservices important and how various frameworks or technology stacks play nicely together.
So today we’ll talk about the features that make a microservices architecture possible and how Typesafe’s stack with Play framework and Akka, the toolkit for message-driven applications, enable these features. Maybe they don’t, or maybe there are other stacks that do it better. For now we plan to explore the microservices landscape for a while, so stay with us and suggest where to look next to investigate your favorite frameworks.
What Is Akka?
Akka is a toolkit and runtime for building highly concurrent, distributed, and resilient message-driven applications on the JVM.
Akka employs the actor model for organizing the computation, which means that the code is divided into units, called actors, that perform the computation manipulating only their own mutable state and communicating with each other using immutable messages. The system of actors is connected into a hierarchical structure which gives the immense power of the implied supervision strategies, failure tolerance and contextualizing components by their names.
Recently, I’ve stumbled upon a great transcript of a podcastwith Jonas Bonér, the CTO of Typesafe, where he discusses microservices in detail and what he thinks of the microservices, including the qualities that make a microservices architecture successful.
Before we begin, why not learn more about microservices? Our helpful Exploring Microservices With Java resource page has everything you need to know about developing in a microservices architecture.
Key Properties of Microservices
Jonas Bonér, CTO of Typesafe, lists the following as key properties in a microservices architecture:
- Single responsibility exclusive state
- Asynchronous communication
- Explicit communication protocols
- Distribution and location transparency
Not surprisingly, many of these features, or rather principles, are embodied in the software that Typesafe creates.
As Jonas puts it:
“Typesafe Reactive Platform has a foundation in Akka, and since that's what we all live and breathe it's natural for us to think about the world like this. As you know, customers have used this platform Akka and Play, to build microservices-based apps for years. Actually, even before I knew that they were called microservices-based apps.”
Let’s try to go over these properties one by one and see how the Play Framework and Akka enable them.
Isolation in software systems means that components do not interact directly with each other and the failure in one component stays contained, without compromising the whole system. It is a nice property indeed and is the cornerstone of the microservices architecture which directs you to create distributed components within your system and make them interact through an external channel, making it virtually impossible to break isolation or make one component know about the implementation details of others.
Isolation With Akka
There’s a concept of an ActorRef in Akka. ActorRef is an immutable and serializable handle to an actor. The actor itself is what will be doing the work, the computation, but the ActorRef is how other components can identify and refer to that worker.
Here’s an example of using ActorRef right from the documentation.
In the example above, the ActorRef is obtained from the context in which the system or actors reside, and using this “handle” our code can send messages, telling what the actor that goes by “childName” should do. The best part is, that we have absolutely no access to the internals of that actor and don’t even know if it’ll be on the same JVM or even the same physical machine. If that actor cannot perform the task, we’ll get a note about that, but it absolutely won’t bring us down.
Isolation is embedded into Akka which is perfect to start building the forest of microservices.
The second virtue of microservices is the autonomy. Indeed, components of the same system should be as independent from each other as they can possibly be. If, for example, two different services use the same database and one, suddenly, has to change the schema to accommodate for a future release, you’re in trouble. You need to change the other one as well or do tricks in order to maintain two versions of the database schema simultaneously. NoSQL fans, stop giggling, you have the same problem, if your services are not independent enough.
Initially, it seemed quite hard for me to assess how much a certain stack enables the autonomy, as it is after all fully in developer’s hands. You decide how messy the system you build will be. True, sometimes it’s your teammates, your manager or pure lack of luck, but let’s concentrate on what’s important here: a developer cannot blame anyone besides themselves when they create an unmaintainable monster.
However, I decided that there are three main things that influence whether I spawn a new component as a standalone project or tie it to the existing one, besides being lazy of course.
That is, how easy is it to:
- start a new, but fully functional project
- consume the HTTP API / Database
- integrate it into the global context of your microservices
Indeed, if starting a new project is a no-brainer and you are set to consume an API out of the box, there’s nothing that prevents you from creating an isolated service for any functional need you have. You can chain the calls to other services as needed still having them autonomous enough.
So in terms of starting a new project, the Typesafe stack is pretty decent, I think. They have the Activator project, which is a project starter utility. In a nutshell, Activator includes the sbt build tool, a quick-start GUI, and a catalog of template applications. The templates are perhaps the most useful feature of it.
The best part is that the templates are mostly hosted on Github, here is for example the code for the last websockets and reactive streams example. This means you can observe and explore the code before diving into it, as well as contribute to the template in a user-friendly manner of submitting a Github pull request.
The external API consumption can be done with a myriad of libraries that implement some sort of HTTP client so you can easily use whatever you find yourself most productive with: SpringRestTemplate, Retrofit or similar.
Autonomy With Play and Akka
The Play framework comes with a simple WS library, where WS stands for WebServices, I suppose. The main benefits of which are the fluent API:
and the fact that it executes asynchronously by default, so you get a Future-like object called Promise, into which you can map the consecutive data processing functions to be executed in an asynchronous manner.
Now this asynchronous communication between your services was one of the main features Jonas has mentioned before, remember? Not only can you use the asynchronous computations within a single JVM using actors, for example, but in the same fashion you can query the outside world and connect your microservices together.
This makes Play + Akka combination a fairly reasonable combo for building projects that want to run the microservices architecture. Well, to be honest, it couldn’t be the other way around much, after all Typesafe, which maintain both Akka and Play advocate for microservices and it’d be weird if their own projects didn’t fit the bill.
There are a couple of virtues of microservices that Jonas Bonér mentioned in his podcast interview linked above like the single responsibility principle as well as distribution and location transparency, but these boil down largely to the developer’s mindset and the infrastructure around the individual microservices. Both of which are not the intended topic of this blog post.
However, in this post we looked at what Akka is and how the Play framework, together with Akka, enable isolation of the components in your application. We provided dirty, cheap new project creation, so you wouldn’t be tempted to reuse the same database or couple your microservices into a large hairball, and easy asynchronous consumption of HTTP APIs to make you microservices communicate with each other.
Determine whether you should deploy microservices in your application in this blog post.