In this blog we are gonna learn about messaging and patterns of messaging. We are gonna learn how asynchronous messaging works. Asynchronous messaging provides us a lot of flexibility in our system. As an example, we can take large portions of our system offline and have our users not notice any difference in functionality. We can also enhance scalability of our system. For example, if we notice that certain portion of our system is not able to process asynchronous messages well, then we can add more pieces to that portion. This works well when we are using publish/subscribe kind of messaging instead of point-to-point. We just need to add more consumers for the messages to scale it. Now let us talk about some of the concepts of Distributed Messaging Pattern.
Message Driven Architecture
One of the key elements of Reactive Principles is that Reactive Systems should be using Message Driven Architecture.
- Reactive System put an emphasis on Asynchronous, Non-Blocking messages.
- Messages are sent without waiting for a response.
- The sender may be interested in a response, but it comes asynchronously.
Advantages to Asynchronous and Non-Blocking
- Resources (thread, memory etc.) does not get blocked and are freed immediately. You send a request and you move on to something else and you release the thread which can be used by some other resource.
- Contention is reduced which means that there is scope for higher scalability.
- It also helps us with reliability. For example, if for some reason the external service which we are sending the message is down, since the message we sent is asynchronous, it stores that message in a queue and deliver it whenever that service comes back online.
The Role of Synchronous Messages
- In a Reactive System asynchronous messages should be the backbone which means that you should try to build using asynchronous messages wherever possible.
- Synchronous messages may be used only for the purpose of acknowledgement. This means that if possible, we can acknowledge the receipt of a message synchronously and process it asynchronously.
- The need for synchronous messages should be driven by domain requirements rather than technical convenience. It is often technically convenient for us to build system using synchronous messages but in the long term that convenience factor may lead to bigger problems in terms of inability to scale, reduced reliability etc.
- The best practice is to use asynchronous by default, fallback to synchronous messaging only when you are forced.
In a monolithic architecture, coordination and consensus building happens using database transactions. So if you have multiple pieces of the system that you need to update, you open a database transaction, you update multiple tables, then you commit the transaction, and that’s it. In a distributed system though, this gets more difficult, especially when you use asynchronous messages, because what happens is your application spreads across multiple microservices, and those all communicates asynchronously.
This is where Saga’s come in.
How Saga works?
- The saga pattern provides transaction management using a sequence of local transactions.
- A local transaction is the atomic work effort performed by a saga participant.
- Each local transaction updates the database and publishes a message or event to trigger the next local transaction in the saga.
Failure in Sagas
- If a local transaction fails, the saga executes a series of compensating transactions that undo the changes that were made by the preceding local transactions.
- The Saga then completes with a failure.
- The Saga retries a compensating actions in case of failure This requires idempotence.
Communication between Reactive Microservices can be
- Each microservice can directly depend on other microservices, sending messages in a point-to-point fashion.
- Each microservice can leverage a publish/subscribe message broker or bus to decouple it from another service.
Point to Point Pattern
- A point-to-point channel delivers a message to exactly one of the consumers that is reading from the channel.
- Each service depends on other services directly.
- Services are directly coupled to each other APIs.
- Services know about and understand their dependencies.
- Services publish messages to a common message bus.
- Other services subscribe to the messages.
- The publishing service has no knowledge of the subscribing services.
- Subscribing services also has no knowledge of the publishing services.
- Services are completely decoupled as they have no knowledge of each other.
- Services are coupled to only the message format.
So this was all about Distributed Messaging Pattern. I hope you understood all the concepts of Distributed Messaging Pattern.