Wednesday, May 11, 2022

Pattern: Messaging

Problem

How do services in a microservice architecture communicate?

Solution

Use asynchronous messaging for inter-service communication. Services communicate by exchanging messages over messaging channels.

There are several different styles of asynchronous communication:

  • Request/response - a service sends a request message to a recipient and expects to receive a reply message promptly
  • Notifications - a sender sends a message a recipient but does not expect a reply. Nor is one sent.
  • Request/asynchronous response - a service sends a request message to a recipient and expects to receive a reply message eventually
  • Publish/subscribe - a service publishes a message to zero or more recipients
  • Publish/asynchronous response - a service publishes a request to one or recipients, some of whom send back a reply

Examples

There are numerous examples of asynchronous messaging technologies


public class OrderService {

  ...

  public Order createOrder(long consumerId, long restaurantId,
                           List<MenuItemIdAndQuantity> lineItems) {
    Restaurant restaurant = restaurantRepository.findById(restaurantId)
            .orElseThrow(() -> new RestaurantNotFoundException(restaurantId));

    List<OrderLineItem> orderLineItems = makeOrderLineItems(lineItems, restaurant);

    ResultWithDomainEvents<Order, OrderDomainEvent> orderAndEvents =
            Order.createOrder(consumerId, restaurant, orderLineItems);

    Order order = orderAndEvents.result;
    orderRepository.save(order);

    orderAggregateEventPublisher.publish(order, orderAndEvents.events);

    OrderDetails orderDetails = new OrderDetails(consumerId, restaurantId, orderLineItems, order.getOrderTotal());

    CreateOrderSagaState data = new CreateOrderSagaState(order.getId(), orderDetails);
    createOrderSagaManager.create(data, Order.class, order.getId());

    meterRegistry.ifPresent(mr -> mr.counter("placed_orders").increment());

    return order;
  }

Messaging

In this approach, the producer will send the messages to a message broker and the consumer can listen to the message broker to receive the message and process it accordingly. There are two patterns within messaging: one-to-one and one-to-many. 

We talked about some of the complexity synchronous styles brings, but some of it is eliminated by default in the messaging style. For example, service discovery becomes irrelevant as the consumer and producer both talk only to the message broker. Load balancing is handled by scaling up the messaging system. 

Failure handling is in-built, mostly by the message broker. RabbitMQ, ActiveMQ, and Kafka are the best-known solutions in cloud platforms for messaging.



Event-Driven

The event-driven method looks similar to messaging, but it serves a different purpose. Instead of sending messages, it will send event details to the message broker along with the payload. 

Consumers will identify what the event is and how to react to it. This enables more loose coupling. There are different types of payloads that can be passed:

  • Full payload — This will have all the data related to the event required by the consumer to take further action. However, this makes it more tightly coupled.
  • Resource URL — This will be just a URL to a resource that represents the event.
  • Only event — No payload will be sent. The consumer will know based on on the event name how to retrieve relevant data from other sources, like databases or queues.



There are other styles, like the choreography style, but I personally don't like that. It is too complicated to be implemented. This can only be done with the synchronous style.

That's all for this blog. Let me know your experience with microservice-to-microservice communication.

Resulting context

This pattern has the following benefits:

  • 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
  • The additional complexity of message broker, which must be highly available
  • Request/reply-style communication is more complex

This pattern has the following drawbacks:

This pattern has the following issues:

You may also like

Kubernetes Microservices
Python AI/ML
Spring Framework Spring Boot
Core Java Java Coding Question
Maven AWS