A microservices architecture is an established pattern for building a complex system that consists of loosely coupled modules. It is one of the most talked-about software architecture trends in the last few years. It seems to be a surprisingly simple idea to break a large, interdependent system into many small, lightweight modules that can make software management easier. 

Here’s the catch: After you have broken down your monolith application into small modules, how are you supposed to connect them together in a meaningful way? Unfortunately, there is no single right answer to this question, but as is so often the case, there are a few approaches that depend on the application and the individual use case. 

Two common protocols used in microservices are HTTP request/response with resource APIs and lightweight asynchronous messaging when communicating updates across several microservices. Let’s explore these protocols. 

Types of Communication

Microservices can communicate through many different modes of communication, each one targeting a different use case. These types of communications can be primarily classified in two dimensions. The first dimension defines if the communication protocol is synchronous or asynchronous:

The most common type of communication between microservices is single-receiver communication with a synchronous protocol like HTTP/HTTPS when invoking a REST API. Microservices typically use messaging protocols for asynchronous communication between microservices. This asynchronous communication may involve a single receiver or multiple receivers depending on the application’s needs. 

Representational State Transfer

Representational state transfer (REST) is a popular architectural style for request and response communication, and it can serve as a good example for the synchronous communication type. This is based on the HTTP protocol, embracing verbs such as GET, POST, PUT, DELETE, etc. In this communication pattern, the caller waits for a response from the server.

REST is the most commonly used architectural style for communication between services, but heavy reliance on this type of communication has some negative consequences when it comes to a microservices architecture: 

  1. Multiple round trips (latency) – The client often needs to execute multiple trips to the server to fetch all the data the client requires. Each endpoint specifies a fixed amount of data, and in many cases, that data is only a subset of what a client needs to populate their page. 
  2. Blocking – When invoking a REST API, the client is blocked and is waiting for a server response. This may hurt application performance if the application thread is processing other concurrent requests.
  3. Tight coupling – The client and server need to know about each other. It increases complexity over time and reduces portability.

Messaging

Messaging is widely used in a microservices architecture, which follows the asynchronous protocol. In this pattern, a service sends a message without waiting for a response, and one or more services process the message asynchronously. Asynchronous messaging provides many benefits but also brings challenges such as idempotency, message ordering, poison message handling, and complexity of message broker, which must be highly available. 

It is important to note the difference between asynchronous I/O and the asynchronous protocol. Asynchronous I/O means that the calling thread is not blocked while the I/O operations are executed. This is an implementation detail in terms of the software design. The asynchronous protocol means the sender does not wait for a response.