Implement a distributed transaction in microservices software system using Saga pattern
Saigon Technology: AI-Driven Software Development Company in Vietnam with Global Presence
We expedite your software development projects with advanced technologies, an Agile mindset, and ISO standards.
1. Context and problem
With relational databases, we usually find the concept of transaction. Transaction is a single unit of work which may contain multiple operations that are ensured to be all occur or none occur.
Transactions should have ACID properties: atomic, consistent, isolated, and durable. Within a single service, transactions are usually easy to be ACID. When it comes to cross-service, data consistency requires a cross-service transaction management strategy.
In a distributed system/multi-services architecture:
Microservices architecture usually takes the approach of database-per-microservice model. It provides many benefits with data isolation, independency and scaling ability. However, ensuring data consistency across different databases is a challenge.
Let’s take an example of the order processing logic:
1. Client: Submit checkout order
2. Order API: Save order to database
3. Account API: Create transaction and deduct account balance
4. Payment API: Save payment to database and request external payment
5. Order API: Mark order as completed
1. If Saving order fails
2. If Creating transaction or deducting account balance fails
3. If Saving payment or requesting external payment fails
4. If Marking order as completed fails
The above workflow is quite complex and requires a distributed transaction coordination logic for the local transactions to execute and compensating actions to run in case of failures. More steps can be added by the time.
Two-phase commit (2PC) protocol, which is also a technique to create a distributed transaction, requires all participants in a transaction to commit or roll back before the transaction is considered as completed. However some participant mechanisms, e.g, NoSQL databases , message brokering, file storage, etc, don't support this model.
Distributed transaction also has some limitations with synchronicity and availability since it needs all participants to be available. Therefore we have another candidate, the Saga pattern.
?2. Saga - The solution
The Saga pattern is a transaction management strategy involves with multiple local transactions. A local transaction is the atomic work performed by a saga participant. Each local transaction makes the changes, e.g, update database, do some external actions, and publishes message or event to trigger the next transaction in the whole saga. If some local transaction fails, the saga will execute a series of specified compensating transactions that reverse/compensate the changes that were made before by the local transactions.
Saga overview flow
?
In Saga patterns:
There are two common saga implementation approaches: choreography and orchestration. Each has its own set of challenges and techniques to manage the workflow.
3. Set up demo projects
Introduction to the demo project:
Overview context:
1. There are three services with their own local transactions.?
2. Client will submit action that triggers the execution of transaction 1.
3. Subsequent messages/events will be fired on status changes to trigger the other transactions.
4. There is a pivot transaction followed by a retryable transaction.
5. If there are failures, messages/events will be fired to trigger corresponding compensating transactions.
Overview system flow
?
Following is the project structure:
?
?
?
Testing instruction:
?
After starting the program:
4. Choreography
Choreography is a way to coordinate sagas where events are exchanged using a message broker or any mechanism without a centralized controller. Each local transaction publishes events that trigger local transactions in other participants. Participants must know each other’s events to be able to handle them.
Choreography Overview
Pros
Cons
Let’s apply to our demo project:?
Choreography-based Saga overview
?
Overview:
1. Client submit action
2. FirstService performs local transaction 1
3. FirstService publishes Transaction1CompletedEvent that triggers SecondService
4. SecondService performs local transaction 2
5. SecondService publishes Transaction2CompletedEvent that triggers ThirdService
6. ThirdService performs local transaction 3 with two steps
7. ThirdService publishes Transaction3CompletedEvent that triggers FirstService to do the complete action transaction
8. FirstService performs complete action transaction
领英推荐
In case of failures:
1. If local transaction 1 fails: transaction fails
2. If local transaction 2 fails:
3. If local transaction 3 fails:
4. If complete action transaction (retryable) fails after many tries:
Examples:
FirstService local transaction 1 (FirstService.cs)
?
SecondService listener for Transaction1CompletedEvent (Program.cs)
?
SecondService listeners for failure events?from transaction 3 and complete action (Program.cs)
5. Orchestration
Orchestration coordinates sagas using a centralized controller. The orchestrator has the responsibilities of specifying the participants local transactions to perform based on events. The orchestrator should also handle failures by specifying the actions to be taken. Status can be managed for monitoring and management purposes.
Orchestrator Overview
Pros
Cons
?
Let’s apply to our demo projec
Orchestrator-based Saga overview:?
Overview:
1. Client submit action
2. FirstService performs local transaction 1
3. FirstService publishes Transaction1CompletedEvent that triggers Orchestrator
4. Orchestrator sends command to SecondService
5. SecondService to performs local transaction 2
6. SecondService publishes Transaction2CompletedEvent that triggers Orchestrator
7. Orchestrator sends command to ThirdService
8. ThirdService performs local transaction 3 with two steps
9. ThirdService publishes Transaction3CompletedEvent that triggers Orchestrator
10. Orchestrator sends command to FirstService to do the complete action transaction
11. FirstService performs complete action transaction
In case of failures:
5. If local transaction 1 fails: transaction fails
6. If local transaction 2 fails:
7. If local transaction 3 fails:
8. If complete action transaction (retryable) fails after many tries:
Examples:
FirstService local transaction 1 (FirstService.cs)
?
SecondService listener for StartTransaction2Command (Program.cs)
?
Orchestrator coordination logic (Orchestrator.cs)
?
Sample use case in an Order processing system
The orchestration-based saga in order processing system
6. Issues and considerations
Some considerations:
Some issues can happen without proper handling:
Suggested countermeasures to reduce or prevent anomalies include:
7. When to use
Use the Saga pattern when you need to:
The Saga pattern is less suitable for:
— END —
Resources
References