Delivering domain events in MSA: how to choose the message broker wisely?

by Dmitriy Pudovkin (dopudovkin@edu.hse.ru)

The purpose of this article is to consider the nuances of delivering domain events in MSA. The article provides arguments in favor of the implicit exchange of domain events in the micro-service architecture (MSA) through third-party service, called a message broker. A list of criteria is being considered that may be useful for choosing a message broker.

Introduction

Microservices architecture (MSA) is a collection of smaller, independently deployable service[1]. Usually, a microservice is responsible for the part of the domain that forms a boundary context. Despite the fact that each microservice is responsible for a certain part of the domain, services have to exchange data with each other. It is important to note that not every data exchange between microservices is relevant to the domain event. Defining the concept of a domain event will determine the requirements for a message broker.

What is domain event?

For example, there is a store service that is responsible for search and displaying information about goods. To display the set of goods this service accesses the goods service, the warehouse service and the price service. In this example, the state of the system has not changed before and after the data transfer. The image with the microservice call diagram is shown below. However, when purchasing a product, different microservices are also called. The key difference is that this action leads to a change in the state of the system. An image with a diagram of microservices calls in this case is shown below. Therefore, the purchase of goods, unlike viewing goods, can be considered a domain event.

Thus, in this article, a domain event is considered as an event that affects or may affect the state of the system[2]. A domain event can cause changes in several different microservices. Let's figure out why explicitly, like in previous example, calling microservices to notify about a domain event may not be the best idea.

Microservices can explicitly transfer data to each other, for example, by calling an HTTP method, or implicitly, for example, by passing a message to a shared storage, that is accessible for other microservices. Thus, explicit data transfer implies that the sender's microservice knows information about the consumer's microservice. Conversely, with implicit data transfer, the consumer service does not know information about the sender's service.

Explicitly calling all microservices for which a domain event needs to be notified is not a secure solution from the point of view of fault tolerance, since external calls to other microservices are not performed within the same transaction. Also, explicitly calling a microservice to notify about a domain event increases cohesion between microservices. In order to notify a new microservice about an existing event, it is necessary to make changes to the microservice that initiates these events. The message broker helps to solve these problems.

What is message broker?

A message broker is a software component (service) that serves as an intermediary between various services of a distributed system[3]. In his component, two main entities are used: the sender and the consumer. The sender sends messages, the consumer reads and processes the messages. Оbviously, this component can reduce cohesion between microservices. The message broker is responsible for routing the message from the sender to the consumer. In addition, the logic of handling the domain event is now entirely on the consumer's side. Thus, the consumer and the sender do not know about each other. The result of implementing a message broker in the previous example is shown in the diagram below. There are many message brokers on the market. What criteria should you pay attention to when choosing a message broker for a specific task in the world of service architecture?

Сriteria for choosing a message broker

This section is devoted to the criteria for choosing a message broker. The following criteria are given below:

  1. Buffer size
  2. Consumption model
  3. Scalability

It is convenient to represent a message broker as a message channel.

There are implementations where the channel buffer size is zero. This means that the message broker is not able to accumulate messages and immediately sends them from the consumer. Thus, if the consumer is not unavailable for some time, he loses some of the messages. This behavior is implemented by Redis Сhannels. Redis Chanel constantly maintains an active TCP connection with the consumer. The lack of logic for saving messages on the broker's side allows messages to be processed in real time. Short-term failures and loss of small portions of messages may be acceptable, for example, when processing a large array of time series data. The scheme of message consumption from a message broker with a zero buffer size is shown below. A message broker that provides message storage on its side significantly increases the level of fault tolerance of the system. If the consumer is unavailable, messages will accumulate in the channel and can be processed after renewal. The scheme of message consumption from a message broker with a non-zero buffer size is shown below. This behavior is implemented by Redis Streams, Kafka, RabbitMQ, Amazon MQ.

Message brokers may vary in their consumption models. There are two models: push and pull models.

With the pull model, the consumer constantly polls the message broker and picks up a new message, then sends a confirmation of successful processing. With the push model, the message broker independently calls the consumer and waits for confirmation of successful processing.

The Pull model transfers the logic of message consumption to the consumer side. The consumer processes the messages as far as possible. This reduces the chance of failure in case of a sudden slowdown in message processing on the consumer side.

The push model allows to transfer the logic of consumption to the side of the message broker in order to implement more complex routing. This behavior is implemented by RabbitMQ. However, it should be understood that the logic of complex routing slows down the broker and limits the maximum speed of message processing by the message broker server. In addition, adding a new consumer may require changes to be made on the message broker's side.

When using a message broker, special attention should be paid to scalability, since the data flow can be quite large. Scalability should be considered from two sides. Scalability of the consumption scheme and scalability of the message broker.

The scalability of consumption schemes is related to the possibility of processing a single message channel by several consumers, in which consumers process different messages. Thus, increasing the number of consumers increases the speed of message processing. However, this violates the order of message processing within the entire channel. Most brokers implement the mechanism of a group of consumers, which allows to combine them into one group. The message broker determines the consumer from the group that will process the message.

The scalability of a message broker means the ability of a message broker to work on multiple servers in a distributed mode. This feature is well implemented in Kafka due to the division of message channels (topics) into parts (partitions)[4]. This allows to process over one million messages per second.

Conclusion

Regardless of the choice of the message broker vendor, this component allows to reduce the cohesion of microservices and divide responsibility between the sender and the consumer, taking on the role of message routing. The above criteria for choosing a message broker allow us to conclude that the choice is directly influenced by the required level of reliability, processing speed and number of messages.

References

  1. Microservices architecture design / Microsoft Learn : [website]. — URL: https://learn.microsoft.com/en-us/azure/architecture/microservices/ (24.12.2023).
  2. Domain events: Design and implementation / Microsoft Learn : [website]. — URL: https://learn.microsoft.com/en-us/azure/architecture/microservices/ (24.12.2023).
  3. What is message broker? / IBM : [website]. — URL: https://www.ibm.com/topics/message-brokers (24.12.2023).
  4. Documentation / Apache Kafka : [website]. — URL: https://kafka.apache.org/documentation/ (24.12.2023).