Microservices Architecture: Communication

In previous article, we discussed the Microservices Architecture. One of the disadvantages is developer must implement the inter-service communication mechanism and deal with partial failure. So in this article, we will take a look at how to handle the microservices communication.

Depending on the scenario and goals of the service, developers often use 4 main communication styles:
- Remote Procedure Invocation (RPI).
- Messaging.
- Domain-specific protocol.
- Idempotent Consumer.

Remote Procedure Invocation (RPI)

In this style, the client uses a request/reply-based protocol to send requests to a service, it assumes that the service will process and reply in a shot time (few seconds at most). If the service need more time to reply, we need to use asynchronous communication based on messaging style, we will explain this approach in the next section.

There are some examples of RPI technologies:
- REST
- gRPC
- Apache Thrift

REST is a popular style for request/reply communication. This style is based on the HTTP protocol.  

Consider the following example:

REST model

The service 1 (S1) and service 2 (S2) exported APIs for client or other services to send request to it. When the client send a REST API request to API gateway to get some information. The gateway will redirect the request to S1 or S2 based on the path of the request, S1 or S2 can handles the request by itself. But sometimes, S1 needs some information from S2, so S1 will send a REST API request to S2. This is a RPI communication pattern, services connect directly to each other by REST API end-points.

The following advantages make the RPI become to very popular:
- Simple and familiar.
- Easy to implement the request/reply. No need to implement message brokers to sending/receiving the request/reply.

However, they also have some disadvantages:
- Usually only support request/reply (synchronous protocol), and not other interaction patterns such as notifications, publish/subscribe or asynchronous protocol (request/async response or publish/async response).
- The client and service must be available for the duration of the interaction.

Messaging

In this communication style, services communicate by exchanging message asynchronously. The client makes a request to service by sending it a message. The service send a different message back to client if it needs to reply. The client assumes that the service will not reply immediately, and the service might be no response.

There are some examples of RPI technologies:
- Apache Kafka
- RabbitMQ

There are two kinds of messaging communication:
- Single receiver message-based communication.
- Multiple receivers message-based communication.

Consider the following examples:

Single receiver model

In single receiver model, the request from client can be implemented as request/reply-based pattern. The services use message-based requests to communicate with other services.

Multiple receivers model

Multiple receiver model is a more flexible approach. You might be using an event bus interface to publish/subscribe events. With this pattern, the event from the message sender will be available for additional subscriber services.

This pattern has the following advantages:
- Loose runtime coupling since it decouples the message sender from the consumer
- Improved availability since the message broker buffers messages until the consumer is able to process them.
- Supports a variety of communication patterns including request/reply, notifications, request/async response, publish/subscribe, publish/async response etc

This pattern has the following disadvantages:
- Request/reply-style communication is more complex
- Additional complexity of message broker, which must be highly available.

Domain-specific protocol

Use a domain-specific protocol for inter-service communication.

There are numerous domain-specific protocols including:
- Email protocols such as SMTP and IMAP
- Media streaming protocols such as RTMP, HLS, and HDS

Idempotent Consumer

Implement an idempotent consumer, which is a message consumer that can handle duplicate messages correctly. Some consumers are naturally idempotent. Others must track the messages that they have processed in order to detect and discard duplicates.

Summary

There are many patterns you can use for microservices communication, depending on the communication type you want to use and your goals.

In my microservice application, I often using RPI and Messaging to handle the inner-service communication.

If I want to publishing my services outside of Docker host or microservices cluster, I will use request/reply-based communication mechanism, protocol such as REST.

If I'm communicating between services internally (within my Docker host or microservices cluster), in some case, I use message-based communication mechanism such as Apache Kafka or RabbitMQ.

Thank you for reading and enjoy.

References

- https://microservices.io/patterns/communication-style/rpi.html
- https://microservices.io/patterns/communication-style/messaging.html
- https://microservices.io/patterns/communication-style/domain-specific.html
- https://microservices.io/patterns/communication-style/idempotent-consumer.html