What is the Saga Pattern and how to implement it in a microservices architecture?
While working with distributed microservice architecture, each handling its own database transactions separately, maintaining the ACID properties cross-service could be a challenge. In this article, we will look into a use case of the online reservation system using the Saga Pattern.
There are primarily two ways of implementing the Saga Pattern namely:
- Execution Orchestrator Pattern
- Choreography Pattern
The goal of either of these two patterns is to make the transaction ACID compliance:
(A — Atomicity, C — Consistency, I — Isolation, and D — Durable)
Let us first start with a monolithic architecture and then divide the monolithic into the required number of microservices so as to implement the Saga Pattern.
Let us now divide the above monolithic system into distributed microservices with their own instance of databases.
Our use case can be broken down into the following microservices:
- Authentication Service: User authentication and request validation to allow access to the genuine users of the system.
- Order Service: Managing the order placed for the resource reservation.
- Payment Service: Managing the payment flow for the resource to be reserved.
- Reservation Service: Managing the final booking of the resource against the validated user.
- Notification Service: Sending any kind of alert or notification to the user upon success or failure of the specific events.
First, we will begin with the Execution Orchestrator Pattern using an Orchestrator Service which is responsible for carrying out the subsequent transaction in the distributed system based on the individual responses from the microservices.
Let us understand the entire flow in detail.
Step 1: The user is validated against each request, upon validation the Orchestrator receives a successful response, else returns an error.
Step 2: The validated user request is now sent for order processing where the state against the requested order is marked as PROCESSING if the request doesn’t exist. Upon success, the Orchestrator delegates the next call to the Payment Service.
Step 3: The call upon being delegated to Payment Service, validates the transaction against the user and the order details. If it fails, the Step 2 transaction needs to be reverted, or else the call is delegated to the next service and the state is marked as PENDING.
Step 4: The Reservation Service validates the booking against the Order details for the user to make sure it's one reservation per order (as per our use case). If it fails, the Step 3 and Step 2 transactions are reverted, else both transactions are successful and their corresponding states are updated.
Step 5: The notification service sends the notification regarding the status of the reservation. It either sends the failure-related alert or any kind of email/SMS notification for the successful booking of the service.
In this case, the Orchestrator runs the workflow needed to reserve a resource against a user. The Orchestrator is responsible for handling failures and successful transactions in the distributed microservice architecture.
Next, we will explore the Choreography pattern using a message queue that is responsible for the entire flow and task execution including the success and the compensating events in case of failures.
When should we use Saga Pattern?
- Saga Pattern is helpful for distributed systems where the components are loosely coupled.
- The system provides support for rollback or compensating events whenever needed.
- Saga Pattern becomes complicated when there is a cyclic dependency among the microservices.
Anomalies with the Saga Pattern
- Lost updates: When one transaction writes without checking for updates from another transaction, the other updates may be lost.
- Dirty reads: When a transaction or a saga reads updates made by a saga that has not yet completed those updates.
- Fuzzy/non-repeatable reads: Whenever a data update occurs between the reads, different transactions read different data, resulting in inconsistency.
In general, remedies for such anomalies generated in the system can be a semantic lock, introducing version files, and a pessimistic view in the services.
But a simplified solution may be offered by tools such as Bit which offers versioning capabilities to track and manage updates. It also comes with a centralized repository for components and documentation, making it easier to understand and manage the state of the system and reducing the risk of fuzzy or non-repeatable reads.
To learn more:
Component-Driven Microservices with NodeJS and Bit
Such tools can make it easier to implement the SAGA pattern in a microservices architecture by improving reliability and resilience, and ensuring data consistency and integrity in the system.
References
- Choreography pattern – Azure Architecture Center
- Compensating Transaction pattern – Azure Architecture Center
Summary
In this article, we learned about the Saga pattern and also the ways to implement it on the microservices architecture. We will continue exploring more in future articles.
Thank you ❤️ for reading this article, feel free to Subscribe, clap👏🏻 and share it.
From monolithic to composable software with Bit
Bit’s open-source tool help 250,000+ devs to build apps with components.
Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.
Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:
→ Micro-Frontends
→ Design System
→ Code-Sharing and reuse
→ Monorepo
Learn more
- How We Build Micro Frontends
- How we Build a Component Design System
- How to reuse React components across your projects
- 5 Ways to Build a React Monorepo
- How to Create a Composable React App with Bit
Saga Pattern for Distributed Transactions was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.