In this post, I will cover different communication patterns between microservices. As microservices have become more industry pattern, it has also become important how these microservices communicate with each other.
The most common pattern for communication has been synchronous REST API calls. But this pattern comes with its own set of trade-offs. Another pattern is asynchronous communication. Let’s dive deeper into these patterns.
Synchronous Calls
The most standard way for services to communicate between themselves is through HTTP synchronous calls. One source service calls a target service. Target service returns with a response that the source service uses for further processing.
In many web applications, a client (front end) calls a backend service (microservice) to fetch or create data.
Similarly, two microservices can communicate with each other through HTTP. Most frameworks provide an HTTP library that allows one service to call another service. For Example – Axios or Feign.
Challenges with Synchronous Communication
Timeout
If service A calls service B to fetch data, but service B takes forever to respond, service A can time out. What happens if the call is going to cause some side-effect on the service B side? In that scenario, there will be data inconsistencies between both services.
Strong coupling
Synchronous communication between services can create strong coupling between services and can be detrimental to microservice architecture overall. Loose coupling was one of the main features of microservices. If any of the services are down, the dependent services might not work the way they were intended.
Circuit Breakers or Retry are some of the ways these challenges can be overcome.
Asynchronous Calls
With event-driven architecture, asynchronous communication has become more popular. One service publishes a message and another service consumes that message. This does not necessarily happen in real-time. Service A publishes a message and still continues to function without knowing in that moment if other services have consumed that message. Consumer services consume the earlier published message when they are ready.
Usually, these services use message-broker to publish and consume the message from. These services may not know each other and offer the advantage of loose coupling.
Another advantage of asynchronous calls is that the message broker offers a retry mechanism. In the scenario, the consumer did not receive the message, the message can be republished.
Challenges with Asynchronous Communication
Message broker
With asynchronous communication, we introduce a centralized entity message broker. If a message broker is down, there will not be any communication between services.
Schema changes
If the publishing service changes the message schema, it can break consumer service unless there is backward compatibility. This defeats the purpose of microservices which allow independent deployments.
Two-phase commit
Publisher service publishes the message as part of business logic. In most cases, it does this by first committing a transaction and then publishing a message. It must perform this action with two-phase commit. But for whatever reason, if the transaction fails and rolled back, then we are in soup since the message has already been published.
In such cases, it is best to avoid a two-phase commit and store the messages in a database on both sides publisher as well consumer.
When to use these patterns?
It’s not very clear when to use Synchronous or Asynchronous calls. When you start designing a system, you will have to make calls and take into account all the trade-offs. Irrespective of that, one can follow certain notions about when to use these patterns
- If you want to query data from another service and want to use that data immediately, use Synchronous communication.
- If a call to another service is allowed to fail and does not bring down the calling service or any dependent services, you can use Synchronous communication without any fancy retry mechanism.
- If a service wants to change the state of certain business logic, in such a scenario, it can publish a message with an Asynchronous communication pattern.
- Two services involved in a business logic do not need to perform the action immediately or do not depend on the results of the action.
Conclusion
In this post, I discussed the communication patterns of microservices. In synchronous communication patterns, one can use HTTP or gRPC protocols. In asynchronous communication patterns, one can use a message broker for publishing and subscribing to messages.
If you are still interested to read about Spring Security, here is my book Simplifying Spring Security.