CQRS Design Pattern
In this tutorial, we are going to talk about Design Patterns of Microservices architecture which is the CQRS Design Pattern. We will use these patterns and practices when designing e-commerce microservice architecture.
CQRS is one of the important pattern when querying between microservices. We can use the CQRS design pattern in order to avoid complex queries to get rid of inefficient joins. CQRS stands for Command and Query Responsibility Segregation. Basically, this pattern separates read and update operations for a database.
Normally, in monolithic applications, most of the time we have 1 database, and this database should respond to both query and update operations. That means a database is both working for complex join queries, and also perform CRUD operations. But if the application goes more complex this query and crud operations will be also is going to be an unmanageable situation.
For example reading database, if your application required some query that needs to join more than 10 tables, this will lock the database due to latency of query computation. Also if we give an example of writing a database when performing CRUD operations we would need to make complex validations and process long business logic, so this will cause to lock database operations.
So reading and writing databases have different approaches that we can define the different strategies to handle that operation. In order to do that CQRS design Pattern offers to use “separation of concerns” principles and separate reading database and the writing database with 2 databases. In this way, we can even use different databases for reading and writing database types like using No-SQL for reading and using relational databases for crud operations.
Another consideration is we should understand our application use case behaviors, if our application is mostly reading use cases and not writing so much, we can say our application is a read-incentive application. So we should design our architecture as per our reading requirements with focusing on reading databases.
So we can say that CQRS Design Pattern separates reads and writes into different databases, Commands perform update data, Queries perform read data.
Commands should be actions with task-based operations like “add item into shopping cart” or “checkout order”. So commands can be handled with message broker systems that provide to process commands in an async way.
Queries have never been modified in the database. Queries always return the JSON data with DTO objects. In this way, we can isolate the Commands and Queries.
In order to isolate Commands and Queries, its best practice to separate read and write databases with 2 databases physically. In this way, if our application is read-intensive which means reading more than writing, we can define custom data schema to optimize for queries.
By this isolation, we can even use different databases for reading and writing database types like using NOSQL document database for reading and using a relational database for crud operations.
How to Sync Databases with CQRS?
But when we separate read and write databases into 2 different databases, the main consideration is to sync these two databases in a proper way.
So we should sync these 2 databases and keep sync always. This can be solved by using Event-Driven Architecture. According to Event-Driven Architecture, when something updates in the write database, it will publish an update event using message broker systems and this will consume by the read database and sync data according to the latest changes.
But this solution creates a consistency issue because since we have implemented async communication with message brokers, the data would not be reflected immediately.
This will operate the principle of “eventual consistency”. The read database eventually synchronizes with the write database, and it can take some time to update the read database in the async process. We discuss eventual consistency in the upcoming tutorials.
So if we come back to our read and write databases in CQRS design pattern, When starting your design, you can take read database from replicas of write database. In this way, we can use different read-only replicas by applying Materialized view pattern that can significantly increase query performance.
Also when we separated read and write databases, it means we can scale them independently. That means if our application is read-incentive, I mean if it is much more query than write, then we can scale only reading databases very fast.
CQRS design pattern comes with separating commands and query databases. So this required syncing both 2 databases with offering event-driven architectures. And with Event–driven architectures, there are some new patterns and practices that should be considered when applying the CQRS design pattern.
Event Sourcing pattern is the first pattern we should consider using with CQRS. Mostly CQRS is used with the “Event Sourcing pattern” in Event-Driven Architectures. So after we have learned the CQRS we should learn “Event Sourcing pattern”, because CQRS and “Event Sourcing pattern” is the best practice to use both of them.