CQRS way
- Typical architecture pros & cons
- CQRS concept
- Code example
- NEventStore
- CommonDomain
- Pros & cons
- Results
Based on Greg Young's notes and OMD Vision team
experience
Typical architecture
- ORM (NH, EF)
- MS SQL
- DDD (Entity, Repository, Service)
- WebApi CRUD (REST) services
What the problem?
Problems
- You can’t do DDD
- Anemic domain model
- No aggregates
- CRUD
- As result Business logic is blur (server, client, dev mind)
- Lazy loading
- Query optimization is punishment
- One repository method for different reason
- Leads to entity pollution
- Data loss due to storing last state
- Doesn’t scale
- Very expensive horizontal scale, and limited vertical
- Transaction and locks for readers
Why do we use
- Experience, it works at least
- Devs understand it
- Mature
- You can google any problem
- Tooling
- Microsoft, Oracle propagation
- They benefit from this architecture!
- There isn't any other option
- or is there?
Free your mind
- Save state vs history
- We are lucky, CQRS started to live in .NET
- Greg Young and Jonathan Oliver are fathers
- CQRS completely different approach
- With pros and cons, all about trade off
- No silver bullet
-
Time for app to lose weight
How?
CQRS
- Command Query Responsibility Segregation concept
- Pros and cons
- Production proven implementation
- NEventStore (MS SQL, Mongo)
- CommonDomain
Concept
Command Query Responsibility Segregation
Concept
Aggregate
- Reply
- Snapshot
Horizontal scale
Advantages #1
- Simplicity due to real DDD
- Aggregate is isolated (logic inside one class)
- Has solid public interface for write only (no pollution)
- Simple unit tests
- Fast read
- Thin read layer on top of data store
- Read database should be at Web server (MS SQL + Shared Memory protocol = ~50% increase)
- Flexible read optimization
- For highload projections MS SQL can be replaced with Redis, Mongo without any problem.
- Time-travel
- Reproduce bug
Advantages #2
- Easy horizontal scaling
- Read side performance linear increases by adding new nodes
- Geo-scaling, due to 100-200ms delay
- On-demand horizontal scaling can be applied
- No data loss due to storing all events
- Audit for free
- Analytics on the board
- Sophisticated reporting
- Users who created >10 companies per month during 3 month at 2012
- Activity stream
- Integration for free due to event sourcing
Disadvantages #1
- Hard to understand at the beginning (eventual vs transactional consistency)
- Feature implementation takes more time
- Extra code should be written (command, event, projection)
- Fit for system with <30% writes
- Hot fixes slower, no possibility to run SQL to fix
- Write side doesn't scale, performance fixed
- Can be increased by snapshots
Disadvantages #2
- Long projection rebuild
- Increases all the time, can be optimized by dev
- Read side is later than write side
- Can be resolved by ManualResetEvent or SignalR
- Painful aggregate refactoring
- Event can not be changed (Converting events, compensation events)
CQRS code examples:
- Controller write
- Command
- Command handler
- Aggregate
- Event
- Projection
- Controller read
- Write database
Controller write
Command
Command handler
Aggregate
Event
Projection
Controller read
Write database
OMD Vision results
- MS SQL 2012, ASP.NET MVC 4, ServiceStack.OrmLite 3
- Read request ~ 30ms (prod) ~ 15ms (local)
- Write request
- 100ms (prod) 30ms (local)
- 200ms fat aggregate (prod) 60ms(local)
- 1.3m events
- 0.5m commits
- The most fat aggregates:
- 1st = 14 054 events
- 2nd = 7 778 events
- 3rd = 7 449 events
- 65 projections 110 tables
- Full rebuild duration ~1d
Questions
Links
CQRS overview
By Vladimir Gaevoy
CQRS overview
- 4,653