Managing distributed data in a microservice architecture

distributeddataproblems

A key characteristic of the microservice architecture is that each service has its own database. This is important to ensure loose coupling but it makes transaction management and querying challenging.

Maintaining data consistency is a challenge

You must implement business transactions that span services but two-phase commit (2PC) is rarely an option.

Querying is a challenge

You must implement queries that retrieve data from multiple services.

Using an asynchronous, microservice architecture.

The solution to these distributed data management problems is to use the Saga pattern and the CQRS pattern. In such an architecture, services communicate asynchronously using domain events, and command/reply messages.

Using sagas to maintain data consistency

eventdrivencreditcheck

Sagas are a transaction model for the microservice architecture. A saga is a sequence of local transactions. Each local transaction updates the data in one service and sends a message/event that triggers the next transaction. For more information, please read the Saga pattern.

Using CQRS views

maintainingviews

CQRS views are a way to implement queries that span services in a microservice architecture. A CQRS view is a replica of data from one or more services that is optimized for a particular set of queries. The service that maintains the view does so by subscribing to domain events. Whenever a service, updates its data it publishes a domain event. For more information, please read the CQRS pattern.

The problem of atomically updating the database and publishing messages

atomicity

You can use an asynchronous architecture to solve the distributed data management challenges in a microservices architecture. However, one major challenge with implementing an asynchronous architecture is atomically updating the database and sending a message.

Consider, for example, the Create Order use case. The service that implements this use case must perform two operations: insert a row into the ORDER table and publish an OrderCreated event. It is essential that both operations are done atomically. If only one operation happened because of a failure then the system would behave incorrectly.

The standard way to atomically update state and publish a message is to use a distributed transaction involving a database and a message broker. However, for the reasons described earlier this is exactly what we do not want to do. Instead, an application must use the Transactional outbox pattern. The Eventuate Tram framework provides an implementation of this pattern.

Learn more

To learn more, please see this overview of Eventuate Tram framework