avatarAndre Lucas

Summary

The article discusses implementing the SAGA pattern in a microservices architecture to manage distributed transactions, using choreography for service coordination and data consistency across multiple services.

Abstract

The article delves into the complexities of managing transactions in a microservices architecture, specifically within a logistics application context. It contrasts the simplicity of transaction management in monolithic applications with the challenges faced in microservices, where each service has its own database. The SAGA pattern emerges as a solution to maintain data consistency across services, with two implementation approaches: choreography and orchestration. The choreography approach is detailed, illustrating how services communicate via events and messages to handle both the "happy path" and "compensable transactions path" (rollback scenarios). The article also provides pseudo-code examples and diagrams to demonstrate the flow of creating, updating, and canceling orders across the order-service, trip-service, and restaurant-service. It concludes with considerations on the benefits and complexities introduced by the SAGA pattern and references additional resources for further reading.

Opinions

  • The author suggests that managing transactions in a monolithic architecture is simpler due to a single database and transaction context.
  • The SAGA pattern is presented as a viable solution for managing distributed transactions in microservices, emphasizing its ability to ensure data consistency.
  • Choreography is favored as an implementation approach for the SAGA pattern, highlighting its decentralized nature where each service produces and listens to events.
  • The article acknowledges the increased complexity that comes with using the SAGA pattern but argues that it is offset by the benefits of scalability, fault tolerance, and data consistency.
  • The use of message brokers like RabbitMQ or Apache Kafka is recommended for implementing the SAGA pattern to achieve loose coupling, scalability, fault tolerance, and responsiveness.
  • The author advocates for the adoption of log aggregation tools to monitor microservices architectures effectively, citing a previous article on the subject.

Microservices — Controlling transactions with SAGA pattern — Choreography

Let’s imagine a scenario where we have a logistic application.

The context is three services:

order-service: In charge of creating orders

trip-service: In charge of managing trips, collecting and delivering orders.

restaurant-service: In charge of managing the restaurant list and its products.

I already wrote about communication between microservices. There are a lot of ways to communicate a service with other. Usually, we can create this communication using message brokers such as RabbitMQ, Apache Kafka, to build an application with loosely coupled, scalability, fault tolerance and responsiveness.

So, the scenario when is created a new order is it:

three microservices communicating between them and with their databases.

after a customer requests a new order, the order—service publishes in a topic and those interested receive the message that a new order has been created.

Problems

  • If happens that the restaurant doesn’t have the product from the new order?
  • If there are any errors at the moment creating the new order?

Transaction in a monolithic service

Before discussing microservices architecture, let’s imagine these services as a module of a monolithic service.

In the monolithic service sure is easier to manage transactions

Food Service — Monolithic Service with a single database
and single transaction in the same service

It happens because in the single service (monolithic) the flow of creating an order happens in the single transaction.

Some frameworks such as Spring provides:

@Transaction
public void execute(){}

Expose provides:

transaction(database) { // Statements here },

both have a programmatic API for beginning, committing and rolling back transactions.

Set of transaction properties — ACID

A transaction is a package of operations and it consists of a set of properties to ensure reliably.

Atomicity — a transaction is a single unit, so if any parts fail (operations) the entire transaction fails.

Consistency — ensure that the database changes state upon a successfully committed transaction.

Isolation — ensure the same state would have been obtained if the transactions were executed sequentially.

Durability — ensure that the transaction will be confirmed

Okay, now we have a brief of how a transaction works and the reason for its existence, we can see the reason that we don’t have mastering of operations when it comes to microservices.

We can see that in the image above, there isn’t consistency, because each microservice has its own database, so we need to use a mechanism to keep the consistency of the data across the databases.

Solution

To resolve those problems that were mentioned before, we have the Saga Pattern.

The Saga Pattern is a sequence of transactions coordinating.

Each transaction updates its database and publishes a message to some message broker to trigger the next transaction.

There are two ways to implement the saga pattern:

  • Choreography
  • Orchestration

Choreography

Step by step — happy path

Happy Path

  1. The order-service receives a POST request to create a new order
  2. The order is created as PENDING
  3. Once the order has been created, an event to order-created-events TOPIC is published
  4. The trip-service and restaurant-service receive the event published by order-service, and creates a trip as PENDING. Also, the restaurant-service checks if the product requested by the order service is available, if so, it runs the business logic to attach the product to the order created and publishes a new event to another TOPIC, order-confirmed-events
  5. The order-service receives the event from order-items-events TOPIC, it is updated with the list of the items and also updated the status as CONFIRMED
  6. Once the order has been its status updated, it publishes an event to the TOPIC order-update-event
  7. The trip-service needs to know that the order was confirmed to change its status from PENDING to CONFIRMED.

Compensable transactions path

Saga uses the compensating transaction to rollback changes.

Step by step — bad path
  1. The order-service receives a POST request to create a new order
  2. The order is created as PENDING
  3. Once the order has been created, an event to order-created-events TOPIC is published
  4. The trip-service and restaurant-service receive the event published by order-service, and it creates a trip as PENDING. Also, the restaurant-service checks if the product requested by the order service is available, in this scenario the product wasn’t available, so, the restaurant-service publishes a cancelled event to the topic order-cancel-event
  5. The order-service receives the event from order-cancel-event TOPIC, and the status is updated as CANCELLED
  6. Once the order has been its status updated, it publishes an event to the TOPIC order-update-event
  7. The trip-service receives the event and changes its status from PENDING to CANCELLED

Pseudo Code

  1. The order-service receives a POST request to create a new order as PENDING
in the order-service

4. The trip-service receives the event published by order-service, and it creates a trip as PENDING.

trip-service

4. The restaurant-service receives the event published by order-service, and it checks if the product requested by the order service is available, if so, it runs the business logic to attach the product to the order created and publishes a new event to the order-confirmed-event TOPIC. If the product is unavailable it publishes an event cancelling the order in the order-cancelled-event TOPIC.

restaurant-service

5. Once the order has been its status updated, it publishes an event to the TOPIC order-update-event

Once the order has been its status updated, it publishes an event to the TOPIC order-update-event

7. And the trip-service gets the update — event always when an order is updated.

Considerations

This pattern enables an application to keep data consistent across multiple services.

The drawback is that we earn more complexity in architecture.

The saga is not just for using with message broker, but using these tools we earn more scalability, fault tolerance, data consistency and other advantages.

For this architecture, you should use a log aggregator, in this post I tell you why.

Full code

References

Read more

Software Development
Software Architecture
Saga Pattern
Development
Microservices
Recommended from ReadMedium