Command-Query Responsibility Segregation - Modern Application Development on AWS

Command-Query Responsibility Segregation

Command Query Responsibility Segregation (CQRS) involves separating the data mutation or command part of a system from the query part. Updates and queries are conventionally completed using a single datastore. You can use CQRS to separate these two workloads if they have different requirements for throughput, latency, or consistency. When you separate command and query functions, you can scale them independently. For example, you can send queries to horizontally-scalable read replicas. For greater separation of command and query functions, you can use different data models and datastores for updates and queries. You can perform writes on a normalized model in a relational database through an ORM (object-relational mapping) and perform queries against a denormalized database that stores data in the same format required by an API (such as data transfer objects or DTOs), which reduces processing overhead.

Figure 9 – Example of an architecture with updates and queries using a single datastore and ORM

Figure 10 – Example of a CQRS architecture with separate command and query workloads and two datastores

Though this example optimizes your architecture for consistent writes in a relational database and very low-latency reads, you might instead want to optimize for very high write throughput and flexible query capabilities. In this situation, you can use a NoSQL datastore, such as Amazon DynamoDB, to get high write scalability on a workload with certain, well-defined access patterns when you add data. You can then use a relational database, such as Amazon Aurora, to provide complex, one-time query functionality. With this option, you can use Amazon DynamoDB streams that send data to an AWS Lambda function that makes appropriate updates to keep the data on Amazon Aurora up-to-date.

Figure 11 – Example of a CQRS architecture on AWS with DynamoDB, Lambda, and Aurora

You can also combine the command part of a CQRS architecture with the event sourcing pattern (see the following section). When you combine these patterns, you can rebuild the service query data model with the latest application state by replaying the update events. It is important to remember that the CQRS pattern generally results in eventual consistency between the queried datastore and the datastore that is written to.