Microservices Communication Design Patterns

Neeraj Kushwaha
8 min readSep 25, 2022

--

This is the 6th post in a series on microservices architecture. This article is originally published at https://www.learncsdesign.com

You can choose from a wide variety of RPC (Remote Procedure Call) technologies. There are synchronous request/response communication mechanisms, such as HTTP-based REST or GraphQL, or gRPC. Alternatively, they can use asynchronous, message-based communication mechanisms such as AMQP (Advanced Message Queueing Protocol) or STOMP (Simple/Streaming Text Oriented Messaging Protocol). Additionally, there are a number of different message formats. These formats can be human-readable, such as JSON and XML. They could also use a more efficient binary format such as Avro or Protobuf.

RPC selection factors

Before choosing an RPC mechanism for an API, it’s helpful to think about the style of interaction between a service and its clients. There are two dimensions to client service interaction.

The first dimension is whether the interaction is one-to-one or one-to-many.

  • One-to-one — Each client request is handled by exactly one service.
  • One-to-many — Each client request is handled by multiple services.

The second dimension is whether the interaction is synchronous or asynchronous.

  • Synchronous — The client may even block while it waits for a response from the service.
  • Asynchronous — Clients don’t block, and the response, if any, isn’t always sent immediately.

One-to-one interactions

  1. Synchronous Request/Response — A service client requests a service and waits for a response. A tight coupling of services is the result of this style of interaction.
  2. Asynchronous Request/Response — A service client sends a request to the service, which replies asynchronously.
  3. One-way notifications — A client sends a request to service but is not expecting a response.

One-to-many interactions

  1. Asynchronous Publish/Subscribe — Clients publish notification messages, which are consumed by one or more subscribing services.
  2. Asynchronous Publish/Async responses — In this scenario, a client publishes a message and then waits for a response from interested services.

Message Formats

RPC is essentially an exchange of messages. The format in which messages contain data is an important design decision. The message format choice can impact the efficiency of RPC, the usability of the API, and its evolvability.

There are two main types of message formats: text and binary.

Text-Based Message Formats

JSON and XML are most popular text-based formats.

Advantages of text-based message formats

  • Human-readable and self-descriptive.

Disadvantages of text-based message formats

  • The messages are verbose.
  • It is unnecessary to contain the names of the attributes/tags in addition to their values.
  • Overhead associated with parsing text.

Binary Message Formats

Thrift, Protocol Buffers (Protobuf), and Avro are the most popular binary formats.

Advantages of binary message formats

  • Metadata is minimal, so the payload is small.
  • Comparatively faster than text-based message parsing.

Disadvantages of binary message formats

  • It’s not human-readable and isn’t self-describing

Remote Procedure Invocation Pattern

When a client requests a service, the service processes the request and sends back a response. While some clients may block while waiting for a response, others might have a reactive, non-blocking architecture.

Proxy interfaces typically encapsulate the underlying communication protocol.

There are various communication protocols to choose from like REST, gRPC and GraphQL etc.

Communicating using the Synchronous pattern

REST (REpresentational State Transfer)

HTTP (HyperText Transfer Protocol) is used to implement REST. REST is based on the concept of resource, which represents a single business object. The HTTP verbs are used by REST to manipulate resources, which are referenced by URLs.

HTTP method Verbs

  1. GET — The GET method requests a representation of the specified resource. Requests using GET should only retrieve data.
  2. HEAD — The HEAD method asks for a response identical to a GET request, but without the response body.
  3. POST — The POST method submits an entity to the specified resource, often causing a change in state or side effects on the server.
  4. PUT — The PUT method replaces all current representations of the target resource with the request payload.
  5. DELETE — The DELETE method deletes the specified resource.
  6. CONNECT — The CONNECT method establishes a tunnel to the server identified by the target resource.
  7. OPTIONS — The OPTIONS method describes the communication options for the target resource.
  8. TRACE — The TRACE method performs a message loop-back test along the path to the target resource.
  9. PATCH — The PATCH method applies partial modifications to a resource.

Specifying REST APIs

APIs must be defined using an IDL (Interface Definition Language). One of the most popular REST IDLs is the Open API Specification, which evolved from the Swagger open-source project.

Challenge of fetching multiple resources in a single request

As REST APIs are usually based on business objects, delivering multiple related objects in a single request is a common challenge when designing a REST API. The client would have to make at least two requests for related objects.

Using query parameters, an API could enable the client to retrieve related resources when it gets a resource. Due to this approach’s lack of scalability, alternative API technologies such as GraphQL and Netflix Falcor have become increasingly popular.

Challenge of mapping operations to HTTP verbs

The other common REST API design problem is mapping the operations you want to perform on a business object to HTTP verbs. The REST API should use PUT to update, but there are multiple ways to update an order including canceling it, revising the order, and so on. One solution is to define a sub-resource like /orders/{orderId}/cancel or /orders/{orderId}/revise to update a particular aspect of a resource or specify a verb in the URL query parameter. But these solutions are not really RESTful.

As a result of this problem, alternatives to REST, such as gRPC, have grown in popularity.

Advantages for REST

  1. It’s easy and familiar
  2. Plugins such as Postman make it easy to test HTTP API from within the browser.
  3. It supports direct request/response communication.

Disadvantages for REST

  1. Only request/response communication is supported.
  2. Reduction in availability due to the requirement for both clients and servers to be online at the same time.
  3. Clients must use service discovery to discover the URLs of service instances.
  4. Getting multiple resources in one request can be challenging.
  5. It can be challenging to map multiple update operations to HTTP verbs.

gRPC

Because HTTP only provides a limited set of verbs, it can be challenging to design a REST API that supports multiple update operations.

This issue is avoided by gRPC, a framework for writing cross-language clients and servers. You define your gRPC APIs using a Protocol Buffers-based IDL, which is Google’s language-neutral mechanism for serializing structured data. It’s a synchronous communication mechanism. Using HTTP/2, clients and servers exchange binary messages in the Protocol Buffer format.

I have written a detailed post on Protocol buffers that you might find interesting.

Advantages for gRPC

  1. APIs with a rich set of update operations are straightforward to design.
  2. The message format is compact and efficient.
  3. Bidirectional streaming makes both RPC and messaging possible.
  4. It enables the interoperability of clients and services written in a variety of languages.

Disadvantages for gRPC

  1. The JS client must do more work to consume gRPC-based APIs than REST/JSON-based APIs.

GraphQL

GraphQL solves the issue of getting multiple resources using a single request. GraphQL is primarily used for querying databases from client-side applications. In the backend, GraphQL specifies to the API how to present data to the client. GraphQL redefines the way developers work with APIs, offering more flexibility and speed to market; it improves client-server interactions, enabling the former to make precise data requests and obtain only what they need.

The GraphQL server provides a client with a schema — a model of the data that can be requested.

Advantages for GraphQL

  1. Clients can specify exactly what they need from the server, and the server will deliver that data in a predictable manner.
  2. API consumers know exactly what data is available and in what form it is since it is strongly typed.

Disadvantages for GraphQL

  1. Regardless of whether a query is successful or unsuccessful, it always returns an HTTP status code of 200.
  2. No built-in caching support
  3. It’s more complicated than REST

Communicating using the Asynchronous messaging pattern

When using messaging, services exchange messages asynchronously. Message-based applications typically use a message broker like RabbitMQ, which acts as an intermediary between services. A service client makes a request to a service by sending it a message. The service instance will send a separate message to the client if it is expected to respond. As the communication is asynchronous, the client does not wait for a response. Instead, the client is written assuming that the response will not be received immediately.

I have written a detailed post on message-oriented middleware using RabbitMQ that you might find interesting.

One-way Notifications

Asynchronous messaging makes it easy to implement one-way notifications. Typically, the client sends a command message to a point-to-point channel owned by the service. The service subscribes to the channel and processes the message. No response is sent back.

Publish/Subscribe

A publish/subscribe interaction style is built-in to messaging. A client publishes a message to a publish-subscribe channel that is read by multiple subscribers.

Publish/Async Responses

It combines elements of publish/subscribe and request/response to form a higher-level style of interaction. A client publishes a message that specifies a reply channel header to a publish-subscribe channel. A consumer writes a reply message containing a correlation id to the reply channel. Utilizing the correlation id, the client matches the reply messages with the request to gather the responses.

Below are links to posts that explain each pattern in more detail.

1. Monolithic vs Microservices Architecture

2. Microservices Design Principles

3. Microservices Design Patterns

4. Microservices Decomposition Design Patterns

5. Microservices Data Design Patterns

6. Microservices Communication Design Patterns

7. Microservices External API Integration Patterns

8. Microservices Observability Design Patterns

9. Microservices Service Discovery Design Patterns

10. Microservices Cross-Cutting Concerns Design Patterns

11. Microservices Security Design Patterns

12. Microservices Deployment Design Patterns

If you like the post, don’t forget to clap. If you’d like to connect, you can find me on LinkedIn.

References

https://microservices.io

--

--

Neeraj Kushwaha

https://www.learncsdesign.com “Walking on water and developing software from a specification are easy if both are frozen”