Fighting Bottlencks with CQRS - ResearchGate

Preview:

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