December is upon us, as is the winter weather in Estonia, where the ZeroTurnaround development team is located. The weather both disappoints me and makes me moody, so let’s talk about microservices. 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.
Recently, I’ve stumbled upon a great transcript of a podcast with 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. This is exactly the information we need for this post!
In the podcast, Jonas explained that he thinks the key properties in a microservices architecture are:
- 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.
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.
The latter is what I want to illustrate with a code snippet. 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.
What the hell have you built. pic.twitter.com/Tq7ktgDWzD
— Jeff Atwood (@codinghorror) June 18, 2013
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.
These are, 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.
Activator, like any project management tool has a neat command line interface which allows you to kick-start and run new projects in a matter of couple CLI commands:
The templates however, provide you with the starter kits for all the possible technologies you might want to use. Want to start an AngularJS project with MongoDB? There’s a template for you: AngularJS Play Mongo. Want websockets and reactive streams in your app? Here you go: Akka Http with Websockets and Reactive Streams! You get the idea.
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.
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 blogpost.
However, in this post we looked at how Play framework, together with Akka, enable isolation of the components in your application, and provide 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.
Stay tuned for the next post in our microservices series, where we most likely explore how Spring stack enables the features that are paramount for a system which is split into independent tiny services.
Subscribe to our newsletter and you won’t miss it: