Reliable Message Delivery Without a Message Broker

Yuri Zinchenko
3 min readJan 19, 2024

--

Photo by kellysikkema on Unsplash

It is expected that the reader is already familiar with the microservice architecture, the message broker pattern, and the concept of a distributed log.

Reliable message delivery

The message broker performs one of the most important tasks in the microservice architecture, namely, it ensures reliable message delivery. Therefore, in addition to providing access to messages, it must store multiple copies of them on different nodes to guarantee fault tolerance, durability, and other properties. Such behavior is usually implemented with the help of a distributed log, which not only reliably stores data but also establishes a total order between all its elements.

There are a lot of benefits to using a message broker, but it also poses some challenges. For example, due to the lack of atomicity between saving in the database and sending a message, we are forced to use the Outbox pattern, which not only helps but also brings other difficulties in the form of duplicate messages.

Reliable data storage

In addition to reliable message delivery, it would be nice if each service in our system could reliably store data, i.e., use some kind of distributed database. Typically, such a database is RSM (Replicated State Machine) and is implemented again with the help of a distributed log — commands (such as “Save New Order” or “Delete Order”) are first reliably stored in the log and only then applied to RSM.

Too many distributed logs

Don’t you think there are too many distributed logs in this design? Actually, nothing prevents the service from sending messages itself, just like a message broker does. For example, after receiving a poll request, the service can return a message created from the corresponding log item (that contains an already applied command) of the distributed database or it can return the message from the cache if it has already been created earlier (while the message broker in this situation will simply get the message from its log).

With this approach:

  1. We will have atomicity because now the database and the log are a single entity. Goodbye, the Outbox pattern!
  2. If every service in our system is built in this way, we will be able to completely abandon the message broker without losing reliable message delivery.

Refusing to use an intermediary in whole or in part may increase the speed of our system:

  1. Now, several components are responsible for messages, not just one (as an addition, there is no single point of failure).
  2. Instead of two writes in the distributed log (each write is quite expensive), now we have only one.

But at the same time, we will lose all of its advantages, will get a more coupled system + there is no such distributed database, at least, I haven’t heard of it, that would provide appropriate access to its log (if I am wrong, please correct me in the comments).

--

--

No responses yet