Published on

How microservices communicate with each other

Table of Contents

One of the main challenges in microservices architecture is setting up communication between the services. This is because services are distributed and thus require more effort to communicate with each other than if they were all in a single process.

How do microservices communicate with each other?

In microservices architecture, each service is typically a separate process that runs in isolation from other services. This means that they need to communicate with each other using network protocols such as HTTP, Remote Procedure Call (RPC), and Advanced Message Queuing Protocol (AMQP).

A few examples of these protocol implementations are:

ProtocolImplementations
HTTPAn HTTP based Web Service
AMQPRabbitMQ, Azure Service Bus
RPCgRPC

Microservices Communication Modes

A fundamental aspect of microservices communication is how the interaction between two microservices is designed and we can refer it as the mode of communication.

This categorization classifies communication into two primary modes:

  1. Synchronous
  2. Asynchronous

Synchronous Communication

In synchronous communication, the calling microservice expects the result in the same request from the called microservice. This mode of communication follows a request-reply pattern and is usually implemented using RESTful WebApis or gRPC.

Synchronous communication is typically used for situations where result is required immediately. For example, a microservice calls an auth service to determine whether the user is allowed to perform a certain action or not.

synchronous communication diagram

Asynchronous Communication

In asynchronous communication, a microservice sends a request to another microservice and the called microservice saves the request and returns an acknowledgment response.

At some later point in time, that could be a few seconds, few minutes, few hours or even days, the called microservice executes the operation that was requested.

Once the operation is executed then the calling microservice is notified about the status of the request either through polling, webhooks or some other mechanisms.

Asynchronous mode of communication is usually used for long running operations. For example, when creating a resource on Azure, its creation is scheduled in the background, and we are notified once it is created.

asynchronous communication diagram

Example: Designing a communication in both synchronous and asynchronous mode

In this example, we'll take one problem and design it's solution using both synchronous and asynchronous modes. This will give us an idea on how a single problem results in different implementations when implemented in both modes. We'll use HTTP based WebAPIs to design both approaches.

Problem

Consider a Transaction service and we want to implement a functionality where clients can download transactions in csv format. Let's see how we can design a solution using both approaches.

Solution 1 - Synchronous approach

This would be relatively simple and most of us would have already seen such implementations. We will have one enpoint where users can send request and it will create and return the csv file.

GET /api/Export?StartDate=<Start Date>&EndDate=<End Date>

Solution 2 - Asynchronous approach

In this approach we would have to do a little bit more work. First, we'll have an endpoint where users send the request for transactions download but instead of returning the csv file, we'll save the request in a database and return an acknowledgment response with a unique identifier for this request.

POST /api/Export

{"StartDate":"<Start Date>","EndDate":"<End Date>"}

We'll also have a job that runs on a schedule and this job will pick up the request from the database at some later point in time. It will create the csv file and upload it to a storage.

Finally, we'll create an additional endpoint that allows clients to inquire about the status of their request - whether it's completed or still pending. If the request is complete then this endpoint will also return the URL where clients can access and download the generated csv file.

GET /api/Export/Status?RID=<Unique Request ID>

Synchronous vs Asynchronous Communication

Now, you might be wondering why would someone ever want to use asynchronous mode of communication. It requires more effort to implement and even more when debugging in case of an issue whereas implementing a synchronous communication is a trivial job.

Asynchronous communication allows us to decouple the submission of a request from its execution. This separation offers the advantage of independently scaling request submissions, which is especially valuable when dealing with long-running operations where execution becomes a bottleneck.

Microservices Communication Forms

Communication form refers to the underlying structure of the communication process between microservices.

Direct

In the case of direct communication, one microservice communicates directly with another. This is the simplest form of communication, but it can also be the least scalable and reliable. The earlier-discussed examples are an illustration of direct communication.

Indirect

Indirect communication involves the use of intermediaries such as message brokers to facilitate communication between microservices. Indirect communication is often used for more complex requests that require multiple microservices to collaborate.

indirect communication diagram

Direct vs Indirect Communication

One of the main design principles of microservices architecture is to avoid any kind of coupling between services. So, we should always strive for indirect form because direct form of communication leads to tight coupling between two services.

For example, in direct communication if a microservice has to call another microservice, it should know the address of the other service and this creates a coupling on the address of the microservice. We can avoid this problem by implementing Service Discovery pattern but that requires some significant effort.

Also, indirect form of communication is more reliable form of communication as message broker can buffer messages and retry failed requests. This also makes it resilient to intermittent issues.

For example, if a microservice is not available, it can still process the messages when it comes back online as those messages will be available in the broker.


Now, with our fundamentals cleared, let's actually look into some of the ways on how microservices communicate:

  1. HTTP based synchronous communication
  2. HTTP based asynchronous communication
  3. gRPC based communication
  4. Message based communication
  5. Pub/Sub communication
  6. Event driven communication

1 - HTTP based synchronous communication

HTTP-based synchronous communication involves sending a request from one microservice to another and waiting for an immediate response before proceeding. It is a direct form of communication and follows request-reply pattern. It is similar to making a regular web API call.

It's useful for scenarios where you require an immediate result from the service, like fetching data or performing an action that relies on the result. However, it can lead to increased latency if services are slow to respond or if the network is congested.

2 - HTTP based asynchronous communication

In HTTP-based asynchronous communication, a microservice sends a request to another service and receives an acknowledgment indicating the request was received. The processing of the request happens separately, and the response might be received later through mechanisms like polling or webhooks. It is also a direct form of communication is suitable for long-running processes that don't need an immediate result, helping to maintain responsiveness in the system.

3 - gRPC based communication

gRPC is a high-performance, open-source RPC framework build by Google. It can also facilitates communication between microservices, both synchronous and asynchronous.

It uses HTTP/2 for transport and Protocol Buffers (protobufs) for serialization, making it efficient, lightweight, and suitable service to service communication. Unlike traditional RESTful APIs, which often use JSON over HTTP/1.1, gRPC uses binary data and multiplexing over HTTP/2, resulting in lower latency and reduced network overhead.

It is also a direct form of communication.

4 - Message based communication

Message-based communication involves services exchanging messages through a message broker or a queue. When one service wants to communicate with another, it sends a message to the broker, which then routes it to the appropriate service.

This decouples sender and receiver, allowing services to operate independently. All message-based communications are of indirect form and are inherently asynchronous.

Message-based communication is particularly useful for scenarios where real-time response isn't crucial or where multiple consumers might need to process the same message.

5 - Publish/Subscribe or Pub/Sub communication

Pub/Sub communication is an extension of message-based communication where messages are published to a topic (or channel) and multiple subscribers can receive those messages. This approach enables broadcasting messages to multiple interested services.

For example, a service can publish events related to user activities, and different microservices can subscribe to relevant events for their specific functionalities.

6 - Event driven communication

You can say Event-driven communication is next step after Pub/Sub communication, where messages are broadcasted and multiple interested services can receive them. However, in event-driven communication, messages are published whenever a change in the system's state or an interesting occurrence happens, regardless of whether any service is actively listening for those messages. This contrasts with pub/sub, where messages are explicitly designed and published based on specific needs.

Communication Matrix

Diagram showing communication matrix

As you can observe from the communication matrix, all message-broker based communications are indirect and asynchronous. However, with HTTP and gRPC, we can implement both synchronous and asynchronous modes of communication, but in the direct form.

Conclusion

In conclusion, setting up communication between microservices is a key challenge in microservices architecture. Microservices typically communicate using network protocols such as HTTP, RPC, and AMQP.

We have seen communication can be divided into modes and forms which have their own pros and cons. We have also seen different types of communication techniques.

Selecting the right approach for various scenarios is crucial for scalability, resilience, and maintainability in microservices-based applications and I hope this post gave you enough information to make the correct decision.