Unlike monolithic architecture, where all app components are tightly coupled and there is a single codebase, microservices architecture implies having a collection of loosely coupled services. These services can be deployed independently from each other and provide great flexibility and productivity.
Due to the benefits that microservice architecture brings, more and more companies begin deploying it. However, it is important to understand the different methods of inter-service communication between these services in order to use the most suitable one for your project.
Synchronous vs asynchronous communication
There are two styles of protocol communication in microservices: synchronous and asynchronous. The choice of a suitable style will depend on your application and its needs.
This communication type implies that one service communicates with another service through the rest endpoint and the calling service has to wait for the response of the other service.
Now, if you have a chain of microservices in which each microservice calls another one, this may cause a big delay. The downtime of your system becomes the sum of the downtime of each microservice. In case one of the services in the chain falls, the service that calls it will fall as well because it will have to wait for a response. As a result, all the calling service’s thread will be blocked. To solve this problem you can use circuit breaker patterns but this will take extra time.
Even though synchronous communication has its drawbacks, there are advantages as well:
- Easy debugging
- Easy implementation
- High reliability
- Low design complexity
Synchronous communication is perfect for apps that involve real-time data like e-commerce apps. For example, when a customer checks the availability of a product, it needs to be validated in real-time. So when a user makes a request, a service needs to wait for another service’s reply in order to provide accurate and valid information.
With asynchronous communication, the calling service does not wait for another service to respond - instead, it will return the request to the user and other services will process the request. This communication style has an obvious advantage: if one of the services fails, then the calling service will continue to work without blocking the whole thread.
Asynchronous communication enables one-to-many communication where a client can send a message to multiple services at once. However, this method also requires careful monitoring because in case of an error, the debugging will be a rather complex procedure.
The biggest advantages of asynchronous communication are:
- Immediate response
- Better failure isolation
- Better performance
The most suitable use case for asynchronous communication would be an application that requires further processing of a request or processing via multiple services. An example would be a banking or financial app where a client makes a query about a loan and the approval process consists of different steps and phases that might be independent of each other.
This communication method is also common in a microservice architecture.
With synchronous and asynchronous communication, services use an HTTP protocol to communicate with each other directly. But in message-driven communication, services use a message broker to push messages to it. So if a service is subscribed to a message broker, it will see the message and will act correspondingly.
This approach removes lots of complexity in terms of inter-service communication. In this case, the services do not need to know how to “talk” to one another: all they have to do is send a message to a broker. As for the message receiving, you can set up the services and subscribe them to certain messages. In this way, the services will only see specific messages and will perform an action only if such a message is received by a broker.
The biggest pitfall of message-driven communication is that the calling service does not know anything about the service that receives the message. However, you can resolve the issue by returning the MessageID to the caller.
Another communication method for microservices architecture is event-driven communication. In this case, we still need a message broker but it does not process or receive any messages. Instead, services write their events to the broker and other services react to the occurrence of these events.
Events can be published in various ways. For example, they can be published to a queue that guarantees delivery of the event to the appropriate consumers or they can be published to a “publisher/subscriber” model stream that publishes the event and allows access to all interested parties. In either case, the producer publishes the event and the consumer receives that event and reacts correspondingly. You can choose between the two options of the message exchange — RabbitMQ and Apache Kafka.
As we already stated, the choice of the right communication method will heavily depend on your application, its purpose, and functionality. As well, the communication method that you choose will impact the performance of your app so you have to consider all pros and cons of each method beforehand.