Reactive Architecture : Distributed Messaging Patterns
In today's rapidly evolving technological landscape, reactive architecture has emerged as a powerful paradigm for building scalable, resilient, and responsive systems. At the core of this architectural style lies distributed messaging patterns, which enable asynchronous and non-blocking communication between components. In this blog post, we will explore the key concepts and advantages of reactive architecture, delve into messaging patterns, and discuss various considerations and challenges involved in their implementation.
What is Asynchronous Messaging ?
Asynchronous Messaging, also called “async messaging” is a communication method where a message is placed in a queue and does not require an immediate response to move forward with processing.
Some of the examples where asynchronous messaging is highly utilized are email, messaging platforms like Whatsapp etc.
What are the Advantages of Asynchronous Messaging ?
1) Resources ( threads , memory ) can be freed.
2) Reduced Contention means potential for higher scalability
3) Messages can be queued for delivery in case the receiver is offline.
Understanding the Cost of Asynchronous Messaging:
1) In a monolithic architecture , coordination and consensus building is often done using transaction.
2) Microservices , Distributed System and async messages all make transactions more difficult.
3) Holding transactions open for long periods results in slow , brittle systems.
What is Synchronous Messaging and when is it needed ?
Synchronous Messaging is a system which requires both parties or components to work simultaneously in real time. In this messaging system when an object or a user sends a message , it must wait for a response from the object it calls.
It is needed when the caller must have a reply like when processing a purchase or logging into an application .
Some more examples where synchronous messaging is used are -
1) Video Call
2) Phone Call
3) Instant Messaging etc....
The Saga Pattern
1) The saga pattern is a way of representing a long running transaction.
2) Multiple requests are managed by saga.
3) Individual requests are run in sequence or in parallel.
4) When all requests complete , the saga is complete.
Failure in Sagas
1) Each request is paired with a compensating action.
2) If any request fails, compensating actions are executed for all completed steps.
3) The saga is then completed with a failure.
4) If a compensating action fails, then it is retired. This requires idempotence(Idempotence is any function that can be executed several times without changing the final result beyond its first iteration).
Timeouts in Distributed Systems:
Timeouts are crucial in distributed systems to ensure system responsiveness and prevent resource wastage. By setting appropriate timeouts, components can define a maximum duration within which they expect a response from other components or services. Handling timeout errors effectively and implementing strategies like retry mechanisms can help mitigate the impact of delays and failures, ensuring the completion of operations in a distributed environment.
Compensating V/s Rolling Back:
1) Applied on top of a previously completed action.
2) Evidence of the original action remains.
1) Implies the transaction has not completed.
2) Removes evidence of transaction.
What to choose?
Compensating actions are often preferred in long-running or distributed transactions where it is challenging to undo changes made by completed steps. They provide more flexibility and allow for handling failures in a more fine-grained and controlled manner. Rollback, on the other hand, can be simpler to implement in certain scenarios, especially when transactions are short-lived and the system can easily revert changes.
Moving Forward with Failures:
Reactive architecture embraces failures as a natural part of the system's behavior. By leveraging elasticity, robust error handling, event-driven communication, supervision, and self-healing mechanisms, reactive systems can adapt and continue functioning despite failures, ensuring resilience and responsiveness.
The Two Generals:
The Two General problem illustrates the impossibility of reaching consensus over an unreliable communication channel.
In The Two General problem we have two armies trying to coordinate a synchronized attack on an enemy. Now both of the armies are at different ends of the enemy territory and have no easy communication channel. The messenger might have to go around the whole territory to reach the other army or to save time they have to go through the enemy territory to deliver a message , but in this process they can be captured and killed. This problem also have other threats like the attack might not be a synchronized attack since the message didn't receive in time or might have never reached to the second general .
Guaranteeing Delivery in Messaging:
The Two General problem shows that over an unreliable network we cannot guarantee message receipt.
So we must be satisfied with either -
1) At Most Once Delivery
2) At Least Once Delivery
At Most Once Delivery: At most once delivery ensures that a message is delivered to the recipient at most once. This approach minimizes the possibility of duplicate messages being processed. However, it does not provide a guarantee of message delivery if failures occur during transmission.
At Least Once Delivery: At least once delivery guarantees that a message will be delivered to the recipient at least once, even in the presence of failures or network issues. This approach typically involves acknowledging message receipt and implementing mechanisms for retrying failed delivery attempts.
We can simulate exactly once delivery using at least once delivery and idempotence or deduplication.
Messaging Patterns : Point-to-Point and Publish/Subscribe:
When managing communications between microservices , there are two distinct approaches we can take -
1) Point-to-Point - Point-to-point messaging involves direct communication between a sender and a specific receiver. In this pattern, messages are sent from a sender to a specific destination or queue, and only the intended receiver consumes the message. It offers a one-to-one communication model, where messages are delivered to a specific recipient. Point-to-point messaging is commonly used when a specific response is required or when messages need to be delivered to a particular destination.
2) Publish/Subscribe - Publish/subscribe messaging, also known as pub/sub, enables one-to-many communication. In this pattern, messages are published to a topic or a channel without specifying individual recipients. Subscribers interested in a specific topic or channel receive the published messages. This pattern allows for decoupling between publishers and subscribers, as publishers don't need to know the exact recipients. It is commonly used for broadcasting messages to multiple subscribers or for event-driven architectures.
Both point-to-point and publish/subscribe patterns have their advantages and use cases within a reactive architecture. Point-to-point messaging offers direct communication and is suitable for scenarios where a specific response or destination is required. On the other hand, publish/subscribe messaging provides a flexible and decoupled communication model, allowing messages to be broadcasted to multiple subscribers.
Message Bus :
In a reactive architecture, a message bus serves as a centralized communication backbone, enabling efficient message exchange between components. It supports both point-to-point and publish/subscribe messaging patterns. By leveraging a message bus , reactive architecture enables seamless communication, scalability and flexibility among components, enhancing the overall system's responsiveness and resilience.
In this blog, we've uncovered the power of reactive architecture and its cornerstone, distributed messaging patterns. As technology evolves, these concepts are essential for building systems that are scalable, resilient, and responsive. Whether it's asynchronous messaging, synchronous messaging, the Saga Pattern, handling failures, or messaging patterns, these are the building blocks of modern software architecture.
By understanding and harnessing these principles, you're better equipped to navigate the complex and ever-changing landscape of modern technology. Reactive architecture not only acknowledges failures but thrives in the face of them, ensuring your systems remain robust.
As you move forward, remember that the key to success lies in adapting to these concepts, making them work for your applications, and staying responsive to the evolving technological terrain. Thank you for joining us on this journey through the world of reactive architecture.
You may reach out to us at firstname.lastname@example.org