Microservices Communication part 1-every programmer must know

Hello Everyone. Microservices communication is the heartbeat of any microservices architecture and designing them could make or break the system. There are just 3 ways of communication between the services i.e synchronous, asynchronous, and hybrid. There is a lot of confusion around this and hence I decided to write an in-depth article on this topic. However, the article went quite long and I decided to split it up into 2 parts. In the first part of this article, we will see the Synchronous Communication between microservices and we discuss different protocols like REST, gRPC, and GraphQL. Then we will see the important aspects to be considered when designing the synchronous communication between microservices. Let's get started.
Before we start this article if you want to understand in-depth on microservices and their design patterns, please go through my article below
What is Microservices Communication?
During Monolith days, communication means connecting our application with external systems like payment gateways. Ever since the microservices architecture evolved, the services got distributed and communication between them forms the heartbeat of the whole architecture. To add to the complexity, every microservice has multiple instances running, and making them talk to the right instance of the right service to get the job done is the most important aspect of any microservices architecture. Let us look at the various ways of communication between the microservices, the important aspects in the following section.
Types of Microservices Communication
This is one of the confusing aspects when we talk about microservices communication but it's quite easy. There are only 3 ways the microservices can communicate as follows
- Synchronous Communication
- Asynchronous Communication
- Hybrid Communication
In this article, we will only look at Synchronous communication. In the next part of the article, we will see about Asynchronous and Hybrid communication between the microservices.
1. Synchronous Communication between Microservices

In synchronous communication, microservices call each other directly to their IP address and this works on an HTTP request-response model using REST API. Microservice 1 either gets the static IP of the Microservice upfront or gets the dynamic IP address (usually private IP) from the service registry like Eureka where all the instances register themselves. If Microservice 2 is down, Microservice 1 will get an error and then the action cannot be performed and the message is lost. We cannot do a retry mechanism in this direct communication.
a. REST API with HTTP/2
The synchronous communication happens over HTTP/1 or HTTP/2 using protocols like REST, gRPC, and GraphQL. HTTP/1 is very slow and it adds some latency hence it is better to use the HTTP/2 to get the benefit of multiplexing (less bandwidth and more efficiency). Usually, all the microservices run inside the private subnet which means they do not have a public IP and cannot be reached directly from the web. Hence we usually use HTTP instead of HTTP(s) for communication inside the cluster.
However, to use HTTP/2 it is mandatory to use it over HTTP(s). In order to use HTTP(s), we need to generate a self-signed SSL certificate and load it to the microservice instances. Then we can easily make REST API calls using HTTP/2 instead of HTTP/1 calls which makes the communication very effective.
You can read my below article to understand in detail about HTTP/2
b. gRPC Protocol
Let's say you have a lot of API calls happening in the system and your application is of an e-commerce or finance nature, then you might need to use gRPC protocol. gRPC is designed for low latency and high throughput communication and it is great for lightweight microservices where latency is critical. gRPC has excellent support for bi-directional streaming and it uses two powerful things under the hood i.e HTTP/2 and Protobuf.
You can take a look at my article on gRPC where I explained in detail
The only problem in gRPC is that debugging gets complicated as we use the binary files called Protobuf. Using a normal HTTP/1 or HTTP/2 REST calls, debugging is easy as we use JSON format in general. But if you weigh the pros and cons, then gRPC should be the ideal choice for the microservices that communicate quite often and needs a low latency.
c. GraphQL Protocol
Another important protocol used in synchronous microservices communication is GraphQL. This also works on top of HTTP but in a different aspect.

GraphQL is the perfect technology to bring your microservices together for aggregating the data as a unified API. We use GraphQL as a data layer for the microservices and combine the data from all these services into a single API that responds to the client. This is synchronous as the GraphQL Server/gateway needs to wait for the response from the other microservices but it aggregates all the data into a single response to the client. This means the client just makes a single API call to get the data it needs without making multiple round trips. This saves a lot of bandwidth at a cost of little latency.
You can check out my article on GraphQL below
Important Aspects of Synchronous Communication in Microservices
Having seen in detail different protocols for synchronous communication, let us look at the important aspects to be followed.
1. Non-Blocking IO
When microservice 1 calls microservice 2, an HTTP Request is made and microservice 1 waits for the HTTP Response. The thread will keep waiting until the response is received and it uses up the system resource. Imagine there are around 100 API calls at the same time from service 1 to 2, then service 1 is gonna be down soon. An example of this is the RestTemplate library in SpringBoot which is synchronous and blocking.
In most programming languages these days we have non-blocking IO libraries available. One such library is the Spring WebClient. It is still synchronous but it will not block the thread until the response is received. Instead, the thread does another job and a notification is received once the response is ready from Microservice 2.
In some use cases, the non-blocking approach uses much fewer system resources compared to the blocking one. So you can consider using a nonblocking IO library depending on the language you use.
2. Load Balancing
Earlier, we discussed each microservices running multiple instances when its scales up on the load. In such cases, it is very very important for us to send the requests in a load-balanced manner to each of the instances. Failing to do so will result in a single instance of a microservice bombarded and hinder the whole system.
There are two ways we can use a load balancer when we call another microservice.
a. Client Side Load Balancing
In a Client Side load balancing, the Catalog Service requests the details of the Product Service from the Service registry and obtains the IP of all the 3 instances. Every Microservice instance has a Client Side load balancer running inside which decides which instance of Product Service to call. Eg: We have a library called Ribbon in Spring Boot. This does the work of Client Side load balancing.

b. Server Side Load Balancing
In Server Side load balancing, we use the domain name of the load balancer that we define for the product service. Under this domain, there are three instances of Product Services registered now. So when Catalog Service calls the Product Service domain name, the load balancer uses its algorithm to route the requests to each of the instances. A good example of such a load balancer is AWS ELB or Nginx etc.

3. Circuit Breaker
Another important aspect of synchronous communication is the Circuit Breaker. Circuit Breaker pattern can allow a microservice to continue operating when a related service fails, preventing the failure from cascading and giving the failing service time to recover. If microservice B is down, the circuit is open and there won't be any calls made from Service A to B. Then service A will check for service B and closes the circuit once service B is up.

You can read about Circuit Breaker in detail in my article
4. Caching
When two services communicate with each other frequently for read operations i.e GET request, we can consider using a Cache rather than calling Microservice 2 every time. This will reduce the load on Service 2 and also reduce the latency of the request as the Cache is blazing fast as it runs on the RAM memory of the machine. There are 2 options to consider in-memory caching or distributed caching.
5. Distributed Tracing
When we have a chain of synchronous communication happening in microservices, it is very important for us to trace the requests to understand where they fail or which service takes a long time to process. Understanding this will help us to build resilient microservices architecture and we need to use the pattern called Distributed Tracing
Please read more on this in my article below,
Summary
In the first part of the Microservices Communication article, we saw about 3 ways of communication between the services i.e Synchronous, Asynchronous, and Hybrid. We dived deep into the Synchronous Communication between microservices and we discussed using different protocols like REST, gRPC, and GraphQL. Then we have seen the important aspects to be considered when designing the synchronous communication between microservices.
Hope you liked this article and thanks for reading this!!!
In the next part of the article, I will walk you all through the Asynchronous and Hybrid communication between microservices and also discuss their advantages and drawbacks.
If you like to get more updates from me,
please follow me on Medium and subscribe to the email alerts.
If you are considering buying a medium membership,
please buy through my referral link





