Synchronous vs Asynchronous communication in microservices integration

Arax Zaeimi
4 min readApr 1, 2020
Image from Microsoft

A primary rule about microservices is the autonomy of each microservice. That means every microservice is responsible for its own criteria and even if experiencing any issue, that should not affect other microservices functionality. What is autonomy? That means we need to meet the following as very basic requirements:

  • Scaleability
  • Independent Deployment
  • Independence from other services in different situations

From the items listed above, we want to focus on the last one which is mostly about the communication architecture of services. The communication is not about the protocol we use (HTTP and REST, AMQP, messaging, and so on). It is about the way we connect microservices to each other and how coupled they are. This can make a significant impact while failures occur. In a microservice-based architecture, it is not out of mind if any millisecond found that a specific service is down or experiencing performance issues.

What are our options for communication? Before going through this subject, it’s good to know the communication types. Microsoft classifies communication types based on their characteristics.

  • Synchronous: The client sends a request and waits for the response. This is the way HTTP is behaving.
  • Asynchronous: The client does not wait for a response and just sends the request to a message broker. AMQP is an asynchronous protocol.
  • Single Reciever: Each request is received and processed by a single receiver.
  • Multiple Receiver: Each request can be processed by zero to multiple receivers. This must be an asynchronous protocol.

You might choose HTTP as a popular approach to connect the microservices. There’s no doubt about the correctness of this choice. It works like a charm. But let’s say it is a good choice when the client is calling and endpoint of your back-end or the API Gateway is calling an internal endpoint. We assume the situation that there are several microservices in your system and to provide a specific data set your services should call each other sequentially until they provide the data and then bring it back to your client. It’s an HTTP call chain. The issues:

  • Blocking and low performance: HTTP is synchronous and the original request doesn’t get a response until all internal HTTP calls are finished. It’s fine until the request calls increase and one of them is blocked. In such a situation, the performance is exponentially affected as additional HTTP requests increase.
  • Loss of Autonomy: In a microservices architecture, it’s ideal that they don’t know about other microservices. If they connect through HTTP they can not be autonomous in any way.
  • Complex Failure Management: If you have a request HTTP call chain and an intermediate microservice fails, all the chain fails. Unless you have a retry scenario with a good circuit breaker strategy to recover such failures. But as the chains get more complex, implementing such a failure strategy gets so hard and in some cases impossible.

Therefore, in order to enforce microservice autonomy and implementing a more stable system, request/response chains should be minimized. Also, it is recommended to only use asynchronous integration (even for queries) for inter-microservice communication (Message- or Event-based). Even if you chose HTTP protocol, it is much better to use HTTP polling independent of the original HTTP request/response cycle.

Basically, synchronous integration is not recommended for internal communications. They don’t allow the microservice to be autonomous and also in a single service failure, overall performance gets impacted. As the synchronous dependencies between microservices raise, the overall response time for the clients gets worse. For the purpose of microservices integration, you can choose message brokers like RabbitMQ or any other queue system.

In conclusion, in a microservice architecture, you can use request/response synchronous (HTTP) protocol for most queries. For delayed responses that might take seconds to finish, you should implement asynchronous communications based on messages. And if there is a request chain to provide some data, it is a much better approach to replicate or propagate data into the initial microservice database. It is not a rule, and it is to lower the sequential calls between microservices. Eventual consistency can be a good approach for syncing such data between bounded contexts and it should be done through asynchronous message-based protocols. And the last but not least, you are about to create autonomous microservices and this is a primary rule, as a result, anything that makes any kind of dependency to other microservices, it is an anti-pattern and should be minimized. And always keep in mind, not to compare theses communication types and say which is better or worse. It’s like comparing a Truck to Bike. It does not make any sense since they are supposed for different purposes. Choose wisely based on what you need and your available resources and conditions in each scenario.

Resources:

.NET Microservices. Architecture for Containerized .NET Applications

Microservices

Microservices: Why Asynchronous Communications?

AMQP vs HTTP — DEV Community 👩‍💻👨‍💻

More about RabbitMQ:

Part 2: RabbitMQ Best Practice for High Performance (High Throughput)

Part 1: RabbitMQ Best Practice

13 Common RabbitMQ Mistakes and How to Avoid Them

--

--