The microservices model prevails in today’s IT system development, where each business is managed by a subsystem –also called a microservice– which operates independently from the other subsystems with which it must cooperate to build the Business Logic.
So, in an e-commerce IT system one can find microservices for customers, invoices, products, orders, sales, suppliers... each microservice having its own data model, where the required information is represented. Of course, as development continues, these models can become more complex, so certain tangible logical barriers need to be established. These barriers are known as Bounded Context and limit the information that belongs to one domain or another. Each Bounded Context can contain certain business or event handling processes so that, from a technical point of view, each Bounded Context could contain more than one microservice.
However, in a context where models are growing and becoming ever more complex, we must start to consider the separation of read and write functions.
Pattern
Command Query Responsibility Segregation (CQRS) is an architectural pattern introduced by Greg Young that, together with Domain Driven Design (DDD), is used in the design of microservices-based systems. CQRS is based on the principle of separating queries and commands, as devised by Bertrand Meyer, where every method is used for queries or for writing data. It goes further than that, though, as there are two models: one for writing and one for reading.
It can be considered as a pattern based on commands and events and, optionally, on asynchronous messages. There may even be two databases (two models do not necessarily involve two databases), one for updates and one for reading, as shown in the diagram below:
Figure 1: Physically separate Read and Write sub-systems.
More evolved CQRS systems implement Event Sourcing, where each event is stored in the order in which it occurred, so that events can be queried, used to restore the system state or reverse actions through “undo” functions.
Benefits
- It allows the principle of single responsibility to be followed more closely. Reading and writing are related but different processes, and having distinct mechanisms allows for better maintenance of the models.
- If the write and read subsystems are physically separated, they can be scaled independently.
- The technologies of the two systems may be different, as the write system could have a different database than the read system.
- This facilitates queries.
Disadvantages
- It increases the complexity of the system by making it difficult to create reentrant software (the ability to interrupt the execution of a routine and safely call it again (re-enter) before its previous invocations are executed) and multithreaded software.
- If Event Sourcing is used, the complexity increases.
- Transactional issues can also lead to data inconsistencies, as a user could query outdated data.
José Luis Antón Bueso, Solution Architect en Altia.