A while back I came up with this diagram that explains Eventuate using microservice architecture patterns.
Let’s look at each of the patterns in turn starting with the Database per Service pattern.
A key characteristic of the Microservice Architecture is loose coupling. There are two types of coupling:
This requirement for loose coupling significantly impacts the database architecture and creates the need for the Database per Service pattern. At a minimum, to avoid design time coupling, services must not share database tables. And, ideally, to reduce runtime coupling, each service should have its own database server.
The Database per Service pattern creates distributed data management challenges. There are two key distributed data management patterns that solve these problems:
Some update operations (a.k.a. commands) need to update data in multiple services. Such an operation typically doesn’t use traditional distributed transactions (2PC) since that’s a type of runtime coupling. Instead, a command that spans services must be implemented using the Saga pattern. A saga is a series of local transactions that are coordinated by the participating services exchanging messages.
As I describe in this series of blog posts about sagas there are two types of saga coordination mechanisms:
Some queries need to retrieve data from multiple services. Since each database is private, the data can only be retrieved using each service’s API. One option is to use API Composition and simply invokes query operations on the services. However, sometimes API composition is inefficient and instead the application must use the CQRS pattern.
The CQRS pattern maintains an easily queryable replica of the data using domain events published by the services that own the data.
Eventuate is a family of frameworks that solve the distributed data management challenges in microservice architecture. By using Eventuate, you can easily implement the Saga and CQRS patterns in your application. Eventuate also provides the messaging primitives for general purpose transactional messaging between services.
The following diagram shows the Eventuate family of frameworks:
There are the following frameworks:
Let’s look at the capabilities of these frameworks.
The Eventuate Tram Sagas framework implements orchestration-based sagas. It provides an easy to use Java-based domain-specific language for the defining the steps of your saga and their compensating transactions. The saga execution engine is embedded within your services, which simplifies the architecture and improves scalability and availability.
Eventuate makes it easy to implement event-driven microservices that use choreography-based sagas and CQRS. It provides an API for publishing and consuming events. Services can use Eventuate to publish events as part of a database transaction that updates business entity. Other services can use Eventuate to consume events with automatic duplicate detection, which ensures that your message handlers are idempotent.
Eventuate provides different event-driven programming models
These higher level capabilities are built on several foundational patterns:
Transactional Outbox - publish a message as part of the database transaction that updates business entities. This pattern is essential for maintaining consistency. Without it, there is a risk of either updating the database without sending a message or sending a message without the corresponding database update.
Idempotent Consumer - detect and discard duplicate messages by tracking the messages that have already been processed. This pattern handles the scenario where a failure causes the message broker to deliver a message more than once.
This patterns are implemented by both the Eventuate Tram and Eventuate Local frameworks.
To learn more please take a look at the following resources: