Event Sourcing and CQRS are two of the original patterns for data management in a Microservices architecture. In this Blog, we understand the various data management patterns for microservices.
What is Event Sourcing?
At the high-level, Event Sourcing act like storing the state of the application in the form of domain events. I have also used a working example for Event Sourcing using Axon and Spring Boot.
What is CQRS?
CQRS stands for Command Query Responsibility Segregation. Quite a mouthful, isn’t it?
Although, it’s not half as bad as it sounds.
Command query responsibility segregation (CQRS) is a programming design pattern that acts as retrieving data and changing data differently. It uses command handlers to simplify the query process and mask complex multi-system changes.
But why do you need it?
Hence, the necessity for this pattern arises from the Database-per-service pattern. The Database per service pattern tells that each microservice must be responsible for its own data. While it looks like neat, this introduces a situation where it can become problematic to implement queries on data scattered over all microservices.
CQRS is one of the most important patterns when querying between microservices. We can use the CQRS design pattern in order to escape complex queries to get rid of inefficient joins. Its stands for Command and Query Responsibility Segregation. Actually, this pattern separates read and update operations for a database.
Let’s consider an example to understand the above CQRS. Let’s suppose we are running a food delivery application. When an order is placed by a customer, the following services could be triggered:-
- Order Service to create an order in the system.
- Restaurant Service to contact the restaurant and place the order in the restaurant’s queue
- Delivery Service to assign a delivery boy to the order and provide him/her the location of the restaurant and delivery location
- Payment Service to handle the payment for the order.
Generally, all the above services deal with particular functionality. Each of them can have its own database. So, they can have their own set of business rules.
Moreover, if we want to provide a view to the customer about the entire Order lifecycle. This site should show everything which has happened in the life of an order. Probably, such a view will need data from each of the above services.
How do we tackle this?
There are many ways to tackle this. One common way is to aggregate the data from each of those microservices by calling interfaces exposed by the services. Although, this leads to unwanted in-memory joins. This also leads to tight coupling connecting the aggregator application and the individual microservices.
Another approach is to maintain a distinct query store. This query store preserves the query-specific view. Eventually, this query store is built by listening to domain events from individual microservices. In the case of the Order lifecycle example, such a query store could maintain an up-to-date view of the order’s lifecycle ready to be served whenever the user requests.
Another reason for CQRS might be found when we look at “User Interface“. Generally, the user interfaces create a need to look at our data in different ways. The user has requirements to see certain pieces of information together to perform certain actions. Although, this view might differ from the underlying domain model.
CQRS starts to make sense when you see a requirement to split your conceptual or domain model into separate models for updates and reads.
Event Sourcing and CQRS
Constantly, Event Sourcing and CQRS are used in conjunction with each other. Jointly, a combination of these two patterns can become a powerful tool for programmers.
In fact, it is often a censorious requirement that an event-sourced system also uses CQRS. It is difficult to query an event-sourced system. And hence, an efficient query store might be a crucial need.
Some of the following advantages of using Event Sourcing and CQRS are:
- We can scale up the command (or update) side separately from your query (or read) side. This could be a better advantage for a system where reads outnumber writes by a huge margin.
- We can choose a different approach for the event store and query store. For example, an event store can also be a classic RDBMS. We can also handle queries using a NoSQL database (like MongoDB).
- Using Event Sourcing and CQRS together, you can primarily get rid of data aggregation patterns.
We are going to understand what’s happening in the above event sourcing diagram :
- We have a command handler. Primarily, all command requests are received here.
- The command processing part takes care of manipulating all the commands and generating appropriate events. These events persisted in the event store. Of course, validations and enforcement of business rules are carried out before the events are persisted. Also, after the events are continued, they are published on a message queue.
- These messaging queues can be a broker like RabbitMQ or Kafka.
- This Query Processing application listens to the events. Generally, this application takes the event payload and persists the data in the query store based on the required read models.
- This query handler part handles the incoming read requests. It regain the data from the query store and outputs it.
The implementation diagram shown is the best way to implement Event Sourcing and CQRS, we will first implement it on a smaller level. Actually, we will perform Event Sourcing and CQRS in the same application.
We can use SpringBoot for our normal application logic. Although, for Event Sourcing and CQRS we will be using Axon Framework. Already we are using the same application for both Event Sourcing and CQRS, we will be using RDBMS (in this case an in-memory H2 database) as both an event store and query store. To connect to the database, we will grasp Spring Data JPA.