Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fighting Bottlenecks with CQRS

Fighting Bottlenecks with CQRS

More at http://verraes.net/ or http://twitter.com/mathiasverraes

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.

ResearchGate DevDay
Berlin, November 30, 2013

Mathias Verraes

November 30, 2013
Tweet

More Decks by Mathias Verraes

Other Decks in Technology

Transcript

  1. Fighting
    Bottlenecks

    with CQRS/ES
    ResearchGate

    Berlin

    Nov 30, 2013
    Mathias Verraes

    @mathiasverraes

    verraes.net

    View Slide

  2. Student

    of

    Systems
    Meddler

    of

    Models
    Labourer

    of

    Legacy

    View Slide

  3. Blog

    verraes.net
    DDDBE

    domaindriven.be
    Podcast

    elephantintheroom.io

    View Slide

  4. Business Problem

    A Simplified Model

    Command/Query Responsibility Segregation

    Event Sourcing

    Read Model Projections

    Eventual Consistency

    View Slide

  5. Business Problem

    View Slide

  6. Sell a gazillion concert tickets

    to desperate fans
    … in a hurry!

    View Slide

  7. Don’t crash

    during peaks
    Don’t annoy

    our customers
    Don’t sell more

    than we have

    View Slide

  8. A Simplified Model

    View Slide

  9. Model invariants as a

    Presale Aggregate?

    View Slide

  10. #reservedTickets #soldTickets
    #availableTickets
    Presale # Tickets

    View Slide

  11. Model invariants as

    individual Ticket Aggregates

    View Slide

  12. reserved sold
    available
    Individual Ticket status

    View Slide

  13. Command/Query

    Responsibility Segregation

    View Slide

  14. Client
    Remote Façade
    Application Services
    Domain Model
    ORM
    Database

    View Slide

  15. Highly cohesive

    Read + Write
    Model?

    View Slide

  16. Bottleneck

    View Slide

  17. Client
    Database Database
    Remote Façade
    Application Services
    Domain Model
    ORM
    Eventually Consistent

    View Slide

  18. CQRS challenges the assumption

    that reading and writing are

    supposed to share the same
    abstractions.

    View Slide

  19. CQRS challenges the assumption

    that reading and writing are

    supposed to share the same
    models.

    View Slide

  20. CQRS challenges the assumption

    that reading and writing are

    supposed to share the same
    databases.

    View Slide

  21. CQRS challenges the assumption

    that reading and writing are

    supposed to share the same
    applications.

    View Slide

  22. Segregation of read and write

    is a radical form of decoupling.

    View Slide

  23. Client
    Domain Model
    Remote Façade Remote Façade
    Application Svcs Application Svcs
    Domain Model
    ORM ORM
    Database Database

    View Slide

  24. Radical!

    View Slide

  25. Client
    Write
    Model
    Read
    Model

    View Slide

  26. Client
    Write
    Model
    Read
    Model
    DTO
    Commands
    Events

    View Slide

  27. Interact

    with State
    Guard

    Invariants
    Project
    State

    View Slide

  28. Task Based
    UI
    Event
    Store
    Polyglot

    Persistence

    View Slide

  29. View Slide

  30. Event Sourcing

    View Slide

  31. TicketWasReserved [ ticketId, forUser, onDate ]

    View Slide

  32. Ticket state = Ticket history

    !
    TicketWasSold [ toUser ]

    TicketWasReserved [ forUser, onDate ]

    ReservationWasReleased [ ]

    TicketWasReserved [ forUser, onDate ]

    TicketWasPrinted [ inPresale ]

    View Slide

  33. Mature domains already work this way

    !
    AccountWasDebited [ 20 ]

    AccountWasDebited [ 10 ]

    AccountWasCredited [ 100 ]

    AccountWasOpened

    View Slide

  34. BankAccount

    {

    debit(amount) {

    guardThatAccountIsNotOverdraft(amount)

    recordThat(

    new AccountWasDebited(amount)

    )

    }

    }

    View Slide

  35. BankAccount

    {

    apply(AccountWasDebited event) {

    amount = amount - event.amount

    }

    }

    View Slide

  36. BankAccount

    {

    getRecordedEvents() {}

    reconstituteFromHistory(eventHistory) {}

    }

    View Slide

  37. Read Model Projections

    View Slide

  38. TicketWasSold

    TicketWasReserved

    ReservationWasReleased

    TicketWasReserved

    TicketWasPrinted
    Ticket

    !
    !

    View Slide

  39. TicketWasSold

    TicketWasReserved

    ReservationWasReleased

    TicketWasReserved

    TicketWasPrinted
    AvailableTicket

    TotalNumberOfAvailableTickets

    AverageNumberOfTicketsPerBuyer

    AverageNumberOfReleasesPerTicket

    View Slide

  40. Eventual Consistency

    View Slide

  41. Writes are immediately consistent

    Reads are eventually consistent

    View Slide

  42. Many issues stemming from eventual consistency

    can be solved in the user interface

    View Slide

  43. A Ticket can only be sold once.

    How do we know it’s available?

    View Slide

  44. Get a batch of x*2 PossiblyAvailableTickets

    !
    ReserveTicket

    ack/nack

    loop while acks < 3
    To buy x tickets:

    View Slide

  45. More?

    !
    Testing

    Context Mapping

    Event Storming

    Process Managers

    Occasionally Connected Systems

    Reporting

    Legacy Integrations


    View Slide

  46. Questions?
    verraes.net
    @mathiasverraes

    View Slide