Upload
mathiasverraes
View
1.722
Download
3
Tags:
Embed Size (px)
DESCRIPTION
ResearchGate DevDay Berlin, November 30, 2013 How can you sell a gazillion tickets in an hour? This talk will explain how to use CQRS, Event Sourcing, and a strong focus on the problem domain to build a system that deals with peaks, reporting, and occasionally connected devices. More at http://verraes.net/ or http://twitter.com/mathiasverraes
Citation preview
Fighting Bottlenecks
with CQRS/ES
ResearchGate Berlin
Nov 30, 2013
Mathias Verraes @mathiasverraes
verraes.net
Student of
Systems
Meddler of
Models
Labourer of
Legacy
Blog verraes.net
DDDBE domaindriven.be
Podcast elephantintheroom.io
Business Problem A Simplified Model
Command/Query Responsibility Segregation Event Sourcing
Read Model Projections Eventual Consistency
Business Problem
Sell a gazillion concert tickets to desperate fans
… in a hurry!
Don’t crash during peaks
Don’t annoy our customers
Don’t sell more than we have
A Simplified Model
Model invariants as a Presale Aggregate?
#reservedTickets #soldTickets
#availableTickets
Presale # Tickets
Model invariants as individual Ticket Aggregates
reserved sold
available
Individual Ticket status
Command/Query Responsibility Segregation
Client
Remote Façade
Application Services
Domain Model
ORM
Database
Highly cohesive Read + Write
Model?
Bottleneck
Client
Database Database
Remote Façade
Application Services
Domain Model
ORMEventually Consistent
CQRS challenges the assumption that reading and writing are supposed to share the same
abstractions.
CQRS challenges the assumption that reading and writing are supposed to share the same
models.
CQRS challenges the assumption that reading and writing are supposed to share the same
databases.
CQRS challenges the assumption that reading and writing are supposed to share the same
applications.
Segregation of read and write is a radical form of decoupling.
Client
Domain Model
Remote Façade Remote Façade
Application Svcs Application Svcs
Domain Model
ORM ORM
Database Database
Radical!
Client
Write Model
Read Model
Client
Write Model
Read Model
DTOCommands
Even
ts
Interact with State
Guard Invariants
Project State
Task Based UI
Event Store
Polyglot Persistence
Event Sourcing
TicketWasReserved [ ticketId, forUser, onDate ]
Ticket state = Ticket history !
TicketWasSold [ toUser ] TicketWasReserved [ forUser, onDate ] ReservationWasReleased [ ] TicketWasReserved [ forUser, onDate ] TicketWasPrinted [ inPresale ]
Mature domains already work this way !
AccountWasDebited [ 20 ] AccountWasDebited [ 10 ] AccountWasCredited [ 100 ] AccountWasOpened
BankAccount { debit(amount) { guardThatAccountIsNotOverdraft(amount) recordThat( new AccountWasDebited(amount) ) } }
BankAccount { apply(AccountWasDebited event) { amount = amount - event.amount } }
BankAccount { getRecordedEvents() {} reconstituteFromHistory(eventHistory) {} }
Read Model Projections
TicketWasSold TicketWasReserved
ReservationWasReleased TicketWasReserved TicketWasPrinted
Ticket !
!
TicketWasSold TicketWasReserved
ReservationWasReleased TicketWasReserved TicketWasPrinted
AvailableTicket TotalNumberOfAvailableTickets
AverageNumberOfTicketsPerBuyer AverageNumberOfReleasesPerTicket
Eventual Consistency
Writes are immediately consistent Reads are eventually consistent
Many issues stemming from eventual consistency can be solved in the user interface
A Ticket can only be sold once. How do we know it’s available?
Get a batch of x*2 PossiblyAvailableTickets !
ReserveTicket ack/nack
loop while acks < 3
To buy x tickets:
More? !
Testing Context Mapping Event Storming
Process Managers Occasionally Connected Systems
Reporting Legacy Integrations
…
Questions?
verraes.net@mathiasverraes