Image is Copyright of Lightbend
One of the things we have learned through working with some of our customers that they were at the early stage of the Microservices journey; they started experiencing performance issues and reporting that their Apps are not very responsive anymore.
This article will explore inter-service communications as one possible area where strong coupling and synchronous communication can cause lack of scalability and performance degradation.
To illustrate, we are using a mainstream use case, where we have a retailer with an order management system. When taking a closer look, we find that good work has been done on clearing the ball of mud and breaking down the monolith to separate Microservices and create services that are contained, isolated to do one thing and do that thing well, same as the Unix philosophy.
Usually the architecture outcome would be similar to what you see below(Diagram A), where we have external services communication coming through the API Gateway to manage security and service level agreements (SLA), among other things.
For external communications we are using Synchronous Rest, but also, we are using the same protocol for internal service-to-service communication.
The approach would work well for simple processes, however when you add more and more services, as illustrated on (Diagram B), you would end up with too many blocking synchronous calls. In many situations that kind of blocking will not be scalable and will render your Apps unresponsive.
Also, the strong coupling among those services will create interdependence that will lead to what is known as distributed monolith.
Reactive Architecture to the Rescue
Reactive Architecture is an architecture style focusing on creating responsive, resilient and elastic systems, doing so by using decoupling and isolation. Isolating state, time and space to reduce the impact of resource contention and coherency delay. Using non-blocking, Event-driven architecture and asynchronous messaging among other techniques to isolate tim (concurrency, remove wait and blocking) and space (distribution, location transparency).
We are using two different techniques below to accomplish asynchronous service-to-service communication. By doing so, we are creating a more responsive, elastic and resilient system.
Asynchronous Communication using Message Bus
One option, as highlighted in (Diagram C), is to use a Message Bus or a distributed streaming platform, such as Apache Kafka.
Services can send commands to other services, or they can send events where other services subscribe and react to those events. For example, the “Order Management” can send a command to “Payments” to process a payment, or Analytics would react to order create event, notice how blocking happened only to submit order?
The approach would require some business process changes though. Instead of customers waiting for order to complete synchronous notification, they will get an immediate order submitted response and later on they would get a push notification or callback notifying them with successful order completion.
Akka Actors Toolkit
Asynchronous service-to-service communication, using the Akka Actors toolkit, Akka is the implementation of the actor model on the JVM.
For simplification, the Actor is a worker who can run independently with tasks and communicate with workers using messaging. This worker has a mailbox and we have a router that can forward messages or commands to the specific worker. We can also have clusters of actors.
Actors don’t suffer from the multithreading synchronization and blocking issues, as it uses the internal mail box to process one message at a time to handle concurrency.
toolkit for building highly concurrent, distributed, and resilient message-driven applications for Java and Scala, and implementation the Actor model.
You can use the Akka toolkit to build a responsive, resilient and elastic system.
Image Copyright of Lightbend, akka.io
Distributed systems and DevOps
While Reactive and distributed systems are elastic, responsive and resilient, they are hard to manage and monitor.
Some vendors, such as Lightbend, have created frameworks and monitoring capabilities to manage and monitor reactive and distributed systems in production.
Are we reinventing the wheel
Sometimes it’s good to reinvent the wheel to serve different purposes. For instance, winter tires are different from high-performance tires.
It’s true those design patterns are not new, however the technology advances on that front and the new implementations have opened new doors. Have a look at those technologies, such as Akka and Kafka. They are really very impressive and enabling and are opening new doors.
Logic Keepers is part of the Confluent partner network and a consulting partner with Lightbend.
Those are my personal views and do not represent the people I have worked with, the companies I worked for, our consulting partners, or my/our past and present customers in any shape or form. Any resemblance to real life use cases or situations is accidental and not intentional in any way, shape or form.
I hope this is helpful to some, and again I understand other’s experience and views could be completely different than mine and I respect that.