CQRS
Command Query Responsibility Segregation
About
CQRS (Command Query Responsibility Segregation) involves separating the mutation model from the query (look up) model.
Reading data has a lot more request volume.
Mutating data has much less volume, BUT must have availability and must be consistent.
When having multiple Bounded Contexts, querying data from them starts getting complex and heavy.
Solutions
What types of solutions CQRS offers.
Use different patterns inside the project for accessing the database.
(like DAO
vs Repository
)
Create Snapshot for specific information.
Ex.: The bank will create snapshots of the balance so that it does not have to recalculate data since the beginning.
Have projection tables with consolidated data for reading only.
You can create intermediate tables that gather information, saving multiple joins to be done from the relational tables. (Kind of like a View)
Using materialized views.
Use the Database Views, but caches these results.
Must have a solution for reloading the data.
Separate the database for writing and for reading.
Using adequate database types for each purpose.
(like SQL
vs NoSQL
)
Commands (Writes)
Commands represent transformations caused by business rules.
Like:
Transfer money to an account.
Enroll a student in a school.
Make an online purchase.
Emit a NF.
Its preferable to refer them as modifiers or mutators instead of commands.
Domain mutations are excellent work for Domain Models.
Queries (Reads)
Queries are done over data.
Like:
What is the account balance.
Which students got the higher grades in the 2° bimester.
What are the best selling products last month.
Be careful with data calculated on the run, all the time. Maybe they should be calculated on the Domain Model instead.
Usage
The objective would be to replicate the databases, and have one only for reading.
This can be facilitated with Event-Driven Architecture.
People loading reports or visual data, should not disturb the people execution business rules.
To use CQRS, is it mandatory to separate the written data and read data?
Ex.: Having mirrored Databases for Read and Write only.
Not necessarily, you must analyze the performance, the persistence model not always is optimized for querying.
Should the Read databases be NoSQL?
If the objective is to store multiple non-structured projections, YES.
Use of:
Cassandra
MongoDB
HBase
Redis
CouchDB
With Monoliths, Transaction Scripts
Using CQRS
When using simpler architectures, it is a lot more straight forwardd to access the Data base.
There is no real need to use CQRS, since JOIN
on tables are doable, there is probably only a single database.
A usable scenario, would be to speed up some heavy queries with multiple JOIN
s, but having a table with these data duplicated and flattened.
With Domain Model, Clean Arch
Using CQRS
In these more complex architectures, expecially when using Repositories, you shouldn't be using them for querying over data, due to:
Performance loss;
Excessive filters to be added to the Repository;
Unability to join data efficiently.
With Distributed Services, Microservices
In these types of architectures, the essence is on how to query these distributed data.
Using API Composition
Pattern
API Composition
PatternOne way is using API Composition
, invoking each of the service's interfaces to obtain the data, dumping all to memory.
Using CQRS
One way would be deriving/replicating to a second Read-only database, it is a cheap and fast way. So writes are done in a separate database.
But this still have the same problems as maintaining just one database, meaning, there will be too many JOIN
s on tables, the tables are probably not built for the bulk READ queries.
The better way is maintaining a separate database that will have Materialized Views
, which are tables specific for these bulk queries, that have data from all the different services gathered and flattened in one place.
It is possible to update these Materilized View
synchronously during Commands.
It is also possible to use asynchronous and more resilient mechanisms, like publishing events and consuming them on a Queue
.
Last updated