How CQRS separates read and write models
· Category: System Design
Short answer
CQRS splits data models into separate schemas optimized for commands (writes) and queries (reads), improving performance and scalability.
Steps
- Design a write model that enforces business rules and transactional integrity.
- Create read models tailored to specific query patterns and UI requirements.
- Propagate changes from the write side to read sides via events or replication.
- Scale read and write infrastructure independently based on load.
- Accept eventual consistency between write and read models.
Tips
- Use CQRS when read and write patterns differ significantly in complexity or volume.
- Combine with event sourcing for a natural synchronization mechanism.
- Keep read models denormalized and purpose-built for queries.
- Avoid premature adoption; simple CRUD applications rarely need CQRS.
Common issues
- Increased complexity from maintaining multiple models.
- Debugging challenges when read models lag behind writes.
- Data synchronization failures causing stale or incorrect reads.
- Team confusion over which model to use for new features.
Example
# Consistent hashing for service discovery
import hashlib
def get_node(key, nodes):
hash_val = int(hashlib.md5(key.encode()).hexdigest(), 16)
return nodes[hash_val % len(nodes)]
node = get_node('user-123', ['node-a', 'node-b', 'node-c'])
This snippet implements consistent hashing to distribute keys across nodes, a foundational technique in scalable distributed systems.