In a monolithic architecture, all the services & database running are running in the same server, hence it is easy to handle transactions and maintain consistency using the traditional ACID property.
But, when it comes to microservices, services and databases are loosely coupled hence a transaction may take a long journey to complete moreover having multiple databases and communicating with multiple services makes it more complex or difficult to maintain the data consistency.
Hence in case of a distributed transaction, we need some control logic that redoes partial transactions and triggers compensating transactions, in case of a failed transaction, to undo the changes that were made by the preceding transaction.
SAGA Pattern
SAGA pattern is the most popular architectural pattern to implement transactions spanning over multiple MicroServices. It was first introduced in 1987 and is popular since then. The Saga pattern is fully asynchronous.
SAGA is basically a sequence of the local transaction where each service after successful transaction updates data within its local storage. The microservice communicate transaction with each other by publishing events. The other service listens to an event once published and performs the next local transaction.
The above diagram explains the working of the SAGA Pattern. At first, the Order Microservice receives a request to create order. It will first commit a local transaction to create order and then trigger an event to Order Created. The Payment Microservices will listen to this event and will commit the customer payment in its local storage/database and trigger an event Payment Accepted . The Invoice Microservice will listen to it and commit send an invoice to the user. This process will be followed until the order is not successfully completed or the event hasn’t reached Order History Microservice .
If any microservice fails to complete its local transaction or respond in a given time window the next microservice will run compensation transactions to rollback the changes. Say, if the Payment Microservice failed to accept payment due to any reason, it will trigger the Payment Failed event, the Invoice Microservice (next microservice) will listen to this event and will start the rollback process by calling Compensate the Created Order and revert the order.
Ways to implement SAGA Pattern
There are two popular ways to implement SAGA
-
Events/Choreography
There is no central coordinator to trigger events, hence each microservice listens to other events and produces events too for triggering local transactions in other microservices. This is similar to what is explained in the above diagram.
-
Command/Orchestration
In orchestration based SAGA one service is responsible for triggering events or driving other services on what local transaction to execute. The saga orchestrator communicates with each microservice in a command/reply style telling them what operation to be performed.
Advantage
The major advantage of the SAGA pattern is that it helps to maintain data consistency across multiple microservices without tight coupling. Also, since each microservice focuses only on its own local transaction, hence other microservices are not blocked.
Disadvantage
SAGA Pattern is difficult to debug as the number of microservices increases. Also, the SAGA pattern does not provide read isolation hence at one moment a customer could see the order being created, and in the next moment, the same order is removed due to failed transaction.
Further Reading
SAGA pattern can be implemented in real-time using AWS lambda and step function. If you are interested in learning how it can be done, I highly recommend you read Applying the Saga pattern with AWS Lambda and Step Functions.
Do you know System Design is a very important topic in product-based company interviews and almost every tech giant asks about it? At IntMain we have a dedicated section for system design to help you prepare. Read here.