8.5 Command and Query Responsibility Segregation (CQRS)
Isolate data store reads and writes to prevent contentionThis pattern is based on Command and Query Responsibility Segregation by Richardson [20, p. 228, 139], and Microsoft [140]. It was originally defined by Dahan [141] and popularised by Young [142, 143, 144].
8.5.1 Context
Reading data is inefficient, either because it is aggregated from many sources, need expensive joins or transformations, possibly of many kinds
Reads and writes are asymmetrical, leading to a need for separation of concerns due to performance, security, or resilience (see § 7.1) requirements
Reads and writes are contentious
8.5.2 Solution
Split the data store and all associated operations into two partitions: commands for mutating the data and queries for reading the data. Upon processing commands, the command side publishes an event that is eventually consumed by the query side to update the read model (see fig. 24).
The data stores can reside in the same database but can also be physically separated or use different technologies.
The original semantics of the commands focused on the intent of the operation, not the data [141, 142]. Richardson uses a looser interpretation, even mentioning the command-side services handling all the CRUD1 operations – including (simple) queries – focusing instead on separate models [20, p. 233]. Others offer this kind of solution as a separate pattern, such as Fowler’s Reporting Database [145] or Microsoft’s Materialized View [126].
8.5.3 Potential issues
This pattern is difficult to use well and can add unneeded complexity. Consider only using this pattern if the benefits outweigh the risks. For most systems, a CRUD-based approach is both sufficient and more natural. If such, shield the consumers from the underlying implementation. [3, p. 435, 143]
If eventual consistency is employed between the models, it can cause consistency problems if a single client updates data and then tries to query it immediately afterwards. Possible solutions include supplying a warning if the data is currently not up-to-date or having the client update a local copy of the data [20, p. 236].
8.5.4 Example
ExampleEshop implements its own product catalogue. However, the reads and writes to this catalogue differ, sometimes by orders of magnitude. Furthermore, reads require expensive joins and aggregations, as the product page displays many different kinds of data. Fortunately, there is no requirement for strict consistency, as a small delay in updating the product page is manageable.
To address this, the product catalogue uses a separate read database. This database has several prepopulated views of products for different use cases, such as the product page or the search page. Any aggregations, filters or transformations are pre-applied.
8.5.5 Related patterns
This pattern directly facilitates (and is often used with [3, p. 434]) Event sourcing (see § 10.6).
8.5.6 Further reading
- Fowler’s thoughts on CQRS [143] and Event-Driven Architecture [39]
- Newman’s thoughts on CQRS and Event Sourcing [3, p. 434]
- Wikipedia [144]
The read-only nature of the query can be used for several different purposes. Unfortunately, even though their purpose is similar, they differ enough in structure not to be easily merged into a single pattern.
Fowler’s Reporting Database focuses only on the read-only replica to improve performance and scalability (something Richardson sees as a part of CQRS) [145]
Richardson’s Command-side replica moves the read-only store to the client side to relieve stress on a providing service [146]
Microsoft’s Materialized View [126] adds several command handlers, generalising the well-known database feature to distributed data stores