Reactive architecture

Reactive architecture is a type of architecture based on the principle of message exchange.

Message exchange helps reduce coupling between system components, enhancing reusability, enabling independent testing, and simplifying component interaction within the system.

Reactive architecture is not exclusive to microservices or event-driven systems; it can also be implemented in modular monoliths, allowing for a flexible transition to separate, independent components in the future.

It is built upon four principles outlined in the Reactive Manifesto.

график закона

Key concepts:

  • Responsive (availability, responsiveness)
  • Resilient (fault tolerance)
  • Elastic (flexibility, scalability)
  • Message-driven (message exchange)

Amdahl's Law

график закона

Availability
Applications must respond to requests on time. It’s not always necessary to meet strict real-time requirements; soft limits within reasonable boundaries are also acceptable.

Resilience
Applications must remain available even in the event of failures. Mechanisms for achieving this include:

  • Replication
  • Containerization
  • Asynchronous delegation
  • Monitoring of:
    • Resources
    • Logs
    • Failed user actions (business-level monitoring) Monitoring should be based on a "sufficient margin." For example, an average network load of 50% is already a reason to consider adding more resources.

Elasticity, scalability
The architecture should consider load balancing that adapts to various loads and flexible methods for scaling resources.

Mechanisms for achieving this include:

  • Vertical and horizontal scaling

Message exchange

  • Location transparency
  • Non-blocking processing
  • Asynchronous communication

Monoliths typically rely on direct, transactional, synchronous data exchange. The mechanism to achieve ACID is:

  • Atomicity
  • Consistency
  • Isolation
  • Durability

Reactive architectures always involve eventual consistency. To approximate ACID, compensating requests (Compensating Transaction Pattern) are used. One such approach is the Saga pattern.

Compensating requests work through:

  • Choreography (each service listens to what others are doing and adjusts accordingly; each transaction publishes events that trigger transactions in other services)
  • Orchestration (a central service makes decisions, and others follow)

The main problem is that there’s no single state to roll back to, as each service has its own state. If the compensating transaction fails, the question arises: what now?

There are several options, but none of them are ideal:

  • Retry multiple times
  • Notify monitoring about the issue

A simplified interaction example is RxJS.

Services are the main point of interaction.
Snapshots are state sources.
Subscription queues: parameters and data.
Components generate actions directly, responding asynchronously.
Views follow the MVVM model.

CQRS (Command Query Responsibility Segregation) separates responsibilities for commands and queries.

CQRS does not mean that Event Sourcing (storing actions that change state instead of the state itself) must be used.

CQRS

Instead of Event Sourcing, you can use CQRS + Saga.

CQRS includes:

  • Event Bus
  • Command Bus | Query Bus

Saga includes:

  • Commands
  • Compensating transactions

Comments

Popular posts from this blog

Books Every Developer Should Read (In My Opinion)

TypeScript: Why It's Needed and Why It's So Popular

Reactive Architecture at the Code Level