Reactive Architecture
Martin Joseph
Enterprise Solutions Architect | InsurTech | Tech Lead SRE| 8X AWS Certified | 3X Azure | GCP | DevOps Subject Matter Expert | Technical Recruiter | Digital Transformation | Researcher | Career Mentor | Public Speaker
Introduction
The rise of adoption of microservices architecture has led to emerging pattern called reactive.
It revolves around Reactive systems, Reactive Microservices & Reactive programming.
Reactive manifesto, it incorporates the idea, paradigms, methods and patterns from both Reactive Programming and Reactive systems into a set of practical principles that software architect and developers need to apply in their transformative work.
The adoption to Reactive architecture is an enabler in making the business realize the efficiencies.
This comes in handy to enable the design and implementation of a highly concurrent and distributed software that is performant, scalable and resilient, while at the same time consuming resources when deploying, operating, and maintaining it.
Therefore, with the adoption of Reactive principles allows an organization to depend on software for making our diverse and distributed civilization more robust.
What makes a system to be Reactive:
I. Stay Responsive
II. Accept Uncertainty
III. Embrace Failure
IV. Assert Autonomy
V. Tailor Consistency
VI. Decouple Time
VII. Decouple Space
VIII. Handle Dynamics
1. Stay Responsive
Ensure the architecture of the solution that is rolled out always responds in a timely manner. The responsiveness of your digital solution matters a lot in the face of your business and its quality of service, the last link in the chain, bridge to your users, and forms the cornerstone of usability and utility.
Being responsive is not just about low latency and fast response time, but also about managing changes—in data, usage patterns, context, and environment. Such changes should be represented within the application and its data model, right up to its end-user interactions; reactions to change will be communicated to the users of a component, be they humans or programs, so that responses to requests can be interpreted in the right context.
Reactive, responsive applications effectively detect and deal with problems. Reactive applications focus on providing rapid and consistent response times. In the worst-case scenario, they respond with an error message or provide a degraded but still useful level of service. This establishes mutually understood upper bounds on response latency and thereby creates the basis for delivering a consistent quality of service. Such consistent behavior in turn simplifies error handling, builds end-user confidence, and encourages further interaction.
2. Accept Uncertainty
Your architecture should build reliability, regardless of unreliable foundations.
领英推荐
Deploying our solutions in cloud or adopting edge technologies does not make your solution reliable. It is scary for the business when systems fail in the most spectacular and intricate ways this might lead to loss of information, reordering, and corruption, and failure detection is guessing game. The world is full of uncertainty.
Even though there are well established distributed algorithms to tame this uncertainty and produce consistent view of the world, these algorithms may introduce poor performance and scalability characteristics and imply unavailability during network partitions.
The key is to manage uncertainty directly in the application architecture. To design resilient autonomous components that publish their protocols to the world—protocols that clearly define what they can promise, what commands and events will be accepted, and, because of that, what behavior will trigger and how the data model should be used. The timeliness and assessed accuracy of underlying information should be visible to other components, where appropriate so that they — or the end-user — can judge the reliability of the current system state.
3. Embrace failure
4. Assert Autonomy
Design components that act independently and interact collaboratively.
Valuable patterns that foster autonomy include domain-driven design new tab, event-sourcing new tab, and CQRS new tab. Communicating fully self-contained facts — modeled closely after the underlying business domain — gives the recipient the power to make their own decisions without having to ask again for more information. CQRS separates concerns by making decisions about one part of the system in one location (one component), which can then readily be disseminated and acted upon elsewhere—possibly at a much later time.
5. Tailor Consistency
Separate consistency per component to balance availability and performance.
Consistency entails guaranteeing the correctness and integrity of your application and user's data.
Providing more consistency led to less value addition, therefore decreasing the availability, efficiency, and performance of your application.
When possible, design systems for eventual consistency new tab or causal consistency new tab, leveraging asynchronous processing, which tolerates delays and temporary unavailability of its participants (e.g. using an event-driven architecture new tab, certain NoSQL new tab databases, and CRDTs new tab). This allows the system to stay available, eventually converge, and, in the event of failure, automatically recover.
If strong consistency is inherently needed for the correctness of a use-case, it should be applied judiciously and selectively, with clearly defined consistency boundaries, keeping the unit of consistency as small as possible to retain a maximum of scalability and availability.
6. Decouple time
Embrace asynchronous to avaoid coordination and waiting.
It's been said that "silence is golden," and this is a true reflection of software systems in the real world. Amdahi's Law and the Universal Scalability Law show that the ceiling on scalability can be lifted by avoiding needless communication, coordination, and waiting.
With temporal decoupling, we give the caller the option to perform other work, in an asynchronous new tab, rather than be blocked while waiting for the resource to become available. This can be achieved by allowing the caller to put its request on a queue, register a callback new tab to be notified later, return immediately, and continue execution (e.g., non-blocking I/O new tab). A great way to orchestrate callbacks is to use a Finite State Machine new tab (FSM), other techniques include Futures/Promises new tab, Dataflow Variables, new tab Async/Await new tab, Coroutines new tab, and composition of asynchronous functional combinators new tab in streaming libraries.
7. Decouple Space
Create flexibility by embracing the network.
System architecture for solutions should embrace the existence of service components that can live in multiple locations, this comes in handy when parts of the underlying hardware malfunction or are inaccessible.
Spatial decoupling enables replication, which ultimately increases the resilience of the system and availability. By running multiple instances of a component, these instances can share the load. Thanks to location transparency, the rest of the system does not need to know where these instances are located but the capacity of the system can be increased transparently, on-demand. If one instance crashes or is undeployed, the other replicas continue to operate and share the load. This capability to fail-over is essential to avoiding service disruption.
8. Handle Dynamics
Continuously adapt to the varying demand and resources.
Well said Martin Joseph??
Cloud Engineer @ MIT esp | Cloud Automation | AI | AWSx3 | Azurex1 | Serverless | FinOps | Terraform |BSc (Hons) EEE | AMIE(SL) | A.Eng(ECSL) | UOP
7 个月Well written! Martin Joseph
Engineering Manager and Tech Lead passionate about building great projects, processes and teams | Mentor | Manager | Developer | Qt | C++ | .NET
7 个月I think adoption today is a key value of any architecture