Microservices are a hot topic these days. A lot has been written about them and a lot of people and companies have started building them. Some say they the concept is nothing new and I have yet to find a clear and widely accepted definition of a microservice. The one I like I have found in a book written by Jonas Bonér:
“Microservices-Based Architecture is a simple concept: it advocates creating a system from a collection of small, isolated services, each of which owns their data, and is independently isolated, scalable and resilient to failure.”
I am not saying that the definition is perfect however I liked it because it focuses on scalability and resilience. The last few services I built lately had to be able to handle a high load. This meant that the service had to be scalable and resilient. We build the APIs on the Openshift platform using apache camel (Fuse) as framework. Because of the stateless implementation and the ability of Openshift to ramp up containers with great ease it scales perfectly. However the problem of scalability and responsiveness under high load got me looking for other ways of building similar interfaces. While doing my research I found the term “reactive microservices” and “reactive programming”.
What is reactive programming? I found a nice page explaining “reactive programming” to my liking.
In short it states that: “Reactive programming is programming with asynchronous data streams.” This is not something new, it can be done with a Hub and Spoke system in JMS. You subscribe to a queue and you “react” as soon as some message has been placed on the queue. However reactive programming goes further than that. It sees everything as a stream of data. From the call to a database to the simple retrieval of a value from a property file. All is handled as a stream of data. This way of programming has it pros and cons. In post I try to let you see why it is beneficial for micro services.
One of the first hits I came across while looking for a good definition / explanation of reactive programming was the reactive manifesto. Although I find that it is more targeted at reactive systems it is a nice place to start when first looking into “Reactive” as the manifesto simplifies the concept and thus the explanation a lot.
According to the reactive manifesto reactive systems are Responsive, Resilient, Message Driven and Elastic. A reactive service is in essence a reactive system and it must adhere to the same principles.
A reactive service is always responsive. This means that a service must always give a response, no matter what the state of the service is. It shouldn’t be possible for a system to give a time out or not respond at all. This allows dependent system to react accordingly in a timely fashion.
Being responsive even when the service is failing means that the service needs to be resilient. Resilient to failure and thus change. Errors should be handled as fast and thus close as possible to the source. The service should also be able to restore itself. For example, when a database connection is no longer available the system should still be responding. When the connection is restored the service should immediately function properly again.
A reactive service should be able to handle a varying load. This means that it should be able to scale up or down given the amount of requests being sent at a given point. By definition the service should be able to scale by getting more resources or it should be possible to run multiple instances of the same service. The service should be elastic when it comes to handling the load.
Reactive services are message or data driven, by passing messages between the components of a service you can guarantee loose coupling and isolation. Both convenient when you need to scale out the application.
So how does it all translate to a reactive microservice, and reactive programming.
In order to explain it properly I am simplifying the concept a bit. The most important part of reactive programming is that everything is a stream of data. All data that is being received is received as a stream of data. This data can be anything and like a stream it is not pulled but pushed. It does not matter if something is only done once, it is still a stream of data. The subscriber of the stream decides for itself what to do with the “event / message”. It can alter the data, call a new service or just forwards it to the requester.
Because the subscriber is decoupled from the source of the stream one can subscribe more than once. This means that you can easily scale up your subscribers if needed. And an important part in this, is that all messages are processed in a non-blocking fashion. Retrieving the data and processing it is decoupled from each other so the one cannot block the other. This means that by default your transactions are handled in an asynchronous way.
That being sad when a reactive microservice calls a backend service it does not wait for the result, it does not block any further calls, it simply subscribes to the result and continuous processing other requests. As soon as the result comes in via the stream it processes that result and returns it back to the actual client.
All this means that building a micro service conform the reactive principles means that you build a scalable and resilient service.
These days there are a lot of libraries, tool-kits, programming languages that support reactive programming. Some of the more populars once are:
- Akka Streams
These frameworks / toolkists can be used to create reactive microservices. The ones that interested me the most were ReactiveX and Vert.X.
First off, Vert.x. According to the website Vert.x is event driven and non-blocking. It is a toolkit which developers can use to implement network driven applications. You can create a complete application with Vert.x or only use portions of it. But how does this work?
The smallest unit of deployment of Vert.x is called a verticle. A verticle is a piece of code that processes events. A Vert.x application consists out of one or more of these verticles. A single verticle receives a specific type of event and processes this event. An event can be based on almost anything, a network buffer, a timer, an incoming rest call or a message from another verticle.
In short a Vert.x application consists out of verticles that process events. This makes a Vert.x application event or message driven. These verticles run on an event loop. This means that the events are processed on that event loop.
When starting the application Vert.x creates several event loops (the default is 2 per cpu core). A event loop runs in a single thread. This means that when an event is taking too long to being processed it is blocking the loop. This will result in delaying or even blocking the processing of all other events. When you do block the event loop the application will slow down significantly or in worst case scenario it will stop working correctly. That is why the most important reason that the golden rule of Vert.x is: “Don’t block the event loop”. When an verticle takes up to much time of the event loop, Vert.x will automatically log this as an error.
ReactiveX is an API that has been implemented in several programming languages, one of them being Java (RxJava). Several reactive libraries have some form of support for or integration with reactiveX. Vert.x is one of the libraries that has integrated reactiveX.
ReactiveX implements the observer pattern, this is a pattern in which an object (in reactive the observable) “observes” a stream of data and distributes it among its subscribers (can be zero or more). A observable can emit three types of events:
onCompletion and onError are emitted only once or never. Once they have been emitted the observable is closed. An onNext event, the actual data you are interested in, can be emitted N times or never. This means that when subscribing to an observable you do not know if you ever get your onNext (data) event. You might as well receive an onError or onCompletion event before you ever receive the onNext event. This means that your code must act accordingly. It must be able to handle any of the three even types and act accordingly.
An observable can be based on anything, from a simple list to a service call to a remote rest API or a database call. By implementing the observable pattern you decouple the call from the response. This means that no thread will be explicitly blocked when it is waiting for a response. When you implement a micro service according to this principle you can create a highly flexible and responsive service. Even under high load the API will be able to handle your calls, if the backend however is not responding you might not like the answer.
In this blogpost I tried to explain Reactive microservices and how you can implement them on a very high overview. In the coming blogposts I will try to show you with small code examples how you can actually implement them.