cqrs & event sourcing in the wild (scotlandphp 2016)

56
CQRS & EVENT SOURCING IN THE WILD Michiel Rook - @michieltcs

Upload: michiel-rook

Post on 15-Jan-2017

287 views

Category:

Software


0 download

TRANSCRIPT

Page 1: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

CQRS & EVENT SOURCING IN THE WILD

Michiel Rook - @michieltcs

Page 2: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

➤ Java, PHP & Scala developer

➤ Consultant, trainer, speaker

➤ Dutch Web Alliance

➤ make.io

➤ Maintainer of Phing

➤ @michieltcs

Page 3: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

YOU

Page 4: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

RAISE YOUR HAND

IF YOU HAVE

Page 5: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

heard about CQRS / Event Sourcing

RAISE YOUR HAND

IF YOU HAVE

Page 6: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

heard about CQRS / Event Sourcing

followed a tutorial, built a hobby project

RAISE YOUR HAND

IF YOU HAVE

Page 7: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

heard about CQRS / Event Sourcing

followed a tutorial, built a hobby project

used it in production

RAISE YOUR HAND

IF YOU HAVE

Page 8: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

TOPICS

➤ Quick recap

➤ Replays and rebuilds

➤ Event versioning

➤ Concurrency

➤ Scale

Page 9: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

QUICK RECAP

Page 10: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

' Event Sourcing ensures that all changes to application state are stored as a sequence of events.

-Martin Fowler

Page 11: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

ACTIVE RECORD VS. EVENT SOURCING

Account number

Balance12345678 �€ 50,00

... ...

Money WithdrawnAccount number 12345678

Amount �€ 50,00

Money DepositedAccount number 12345678

Amount �€ 100,00

Account CreatedAccount number 12345678

Page 12: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

COMMANDS TO EVENTS

Deposit MoneyAccount number 12345678

Amount �€ 100,00

class DepositMoney { public $accountNumber; public $amount; }

Page 13: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

COMMANDS TO EVENTS

Deposit MoneyAccount number 12345678

Amount �€ 100,00

function depositMoney(DepositMoney $command) { $this->apply(new MoneyDeposited( $command->accountNumber, $command->amount, date())); }

command handler

Page 14: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

COMMANDS TO EVENTS

Deposit MoneyAccount number 12345678

Amount �€ 100,00

Money DepositedAccount number 12345678

Amount �€ 100,00

class MoneyDeposited { public $accountNumber; public $amount; public $timestamp; }

command handler

Page 15: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

AGGREGATES

class BankAccount { public $accountNumber; public $balance; // ... public function applyMoneyDeposited( MoneyDeposited $event) { $this->balance += $event->amount; }

Page 16: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

AGGREGATE STATE

Account number

Balance12345678 �€ 0,00

Money WithdrawnAccount number 12345678

Amount �€ 50,00

Money DepositedAccount number 12345678

Amount �€ 100,00

Account CreatedAccount number 12345678

Account number

Balance12345678 �€ 100,00

Account number

Balance12345678 �€ 50,00

Page 17: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

CQRS + EVENT SOURCING

Domain

UI

Event Bus

Event Handlers

Command

Repository

Data Layer

Database Database

Event Store

commands

events

events

queries DTOs

Aggregates

Page 18: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

PROS AND CONS

➤ Domain fit

➤ Testing

➤ Audit trail

➤ Scalability

➤ Complexity

➤ Library support / maturity

Page 19: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

DISCLAIMER

Page 20: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

REPLAYS AND REBUILDS

Page 21: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

PROJECTIONS AND READ MODELS

User Registered

User Registered

User Unregistered Number of active users?

Page 22: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

PROJECTIONS AND READ MODELS

User Registered

User Deactivated

User Reactivated

Number of active users?User Registered

User Unregistered

Page 23: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

PROJECTIONS AND READ MODELS

User Registered Event HandlerNumber of

active users +1

User Unregistered Event HandlerNumber of

active users -1

Page 24: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

PROJECTIONS AND READ MODELS

Events Event Handler(s) Storage

Page 25: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

ELASTICSEARCH

class CompanyRegistered { public $companyId; public $name; public $street; public $city; }

Page 26: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

ELASTICSEARCH

function handleCompanyRegistered( CompanyRegistered $event) { $this->elasticsearch->index([ 'index' => 'companies', 'type' => 'company', 'id' => $event->companyId, 'body' => [ 'name' => $event->name, 'address' => [ 'street' => $event->street, 'city' => $event->city ] ] ]); }

Page 27: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

READ MODEL UPDATES

➤ New type

➤ New structure

➤ Based on existing events

➤ Generate from scratch?

Page 28: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

REBUILDING

Stop application

Remove old read model

Loop over events

Apply to read model

Start application

Page 29: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

ZERO DOWNTIME

Loop over existing events

Apply to new read

model

Apply queued events

Start using new read

model

New events Queue

Page 30: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

CHALLENGE: LONG RUNNING REBUILDS

➤ Alternatives:

➤ In memory

➤ Distributed

➤ Partial

➤ Background

Page 31: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

CHALLENGE: SIDE EFFECTS

User RegisteredUser Id 123abc

Email Address [email protected] Handler

Exclude during replays!

Page 32: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

CHALLENGE: TRANSACTIONS

Event Handler

Event Handler

Event

Event Handler

Event Handler ?

Page 33: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

CHALLENGE: EVENTUAL CONSISTENCY

➤ Asynchronous event handlers

➤ Reads eventually return the same value

➤ Compare with ACID

➤ UI?

Page 34: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

EVENT VERSIONING

Page 35: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

DILEMMA

➤ New business requirements

➤ Refactoring

➤ New view on events

Page 36: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

NEW EVENTS / VERSIONS

➤ No longer relevant

➤ Renamed

➤ Additional or renamed field(s)

➤ Too coarse, too fine

Page 37: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

SUPPORT YOUR LEGACY?

➤ Commands can be renamed

➤ Events are immutable

➤ Correct (incorrect) old events with new events

Page 38: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

UPCASTING

Event Store

UserRegistered_V1

Upcaster

UserRegistered_V2

Event Handler

Page 39: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

UPCASTING

class UserRegistered_V1 { public $userId; public $name; public $timestamp; }

Page 40: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

UPCASTING

class UserRegistered_V2 { public $userId; public $name; public $date; }

Page 41: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

UPCASTING

function upcast($event): array { if (!$event instanceof UserRegistered_V1) { return []; } return [ new UserRegistered_V2( $event->userId, $event->name, $event->timestamp->format("Y-m-d")) ]; }

Page 42: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

REWRITING HISTORY

Load (subset of) events

Deserialize

Modify

Serialize

Save/replace

Page 43: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

THINGS TO BE AWARE OF

Upcasting

➤ Performance

➤ Complexity

➤ Existing projections not automatically updated

Rewriting events

➤ Running code that depends on old structure

➤ Breaking serialization

➤ Changing wrong events

Page 44: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

CONCURRENCY

Page 45: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

CONCURRENT COMMANDS

Withdraw MoneyAccount number 12345678

Amount �€ 50,00

Deposit MoneyAccount number 12345678

Amount �€ 100,00

?

Page 46: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

PESSIMISTIC LOCKING

Withdraw MoneyAccount number 12345678

Amount �€ 50,00

Deposit MoneyAccount number 12345678

Amount �€ 100,00

Account number

Balance12345678 �€ 100,00

Account number

Balance12345678 �€ 50,00

wait for lock

lock

Page 47: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

OPTIMISTIC LOCKING

Withdraw MoneyAccount number 12345678

Amount �€ 50,00version 1

Deposit MoneyAccount number 12345678

Amount �€ 100,00version 1

Account number

Balance12345678 �€ 100,00

version 2

ConcurrencyException

Page 48: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

SCALE

Page 49: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

PERFORMANCE

➤ Server

➤ Database

➤ Framework

➤ Language

➤ Serializer

Page 50: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

STORAGE

➤ #events

➤ #aggregates

➤ #events_per_aggregate

➤ Serializer

➤ Event payloads

➤ Costs

Page 51: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

SNAPSHOTS

Events1 Account Created2 Money Deposited3 Money Withdrawn4 Money Deposited

SNAPSHOT5 Money Withdrawn

Events1 Account Created2 Money Deposited3 Money Withdrawn4 Money Deposited5 Money Withdrawn

Page 52: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

SHARDING

➤ Aggregate Id, Type, Event Timestamp, ...

➤ Rebalancing

➤ Distribution

Page 53: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

ARCHIVING EVENTS

➤ Reduce working set

➤ Inactive / deleted aggregates

➤ Historic / irrelevant events

➤ Cheaper storage

Page 54: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

FRAMEWORK COMPARISON

Framework Upcasting Snapshots Replaying

Broadway (PHP) No (PR) No (PR) Not in core

Prooph (PHP) MessageFactory Yes, triggers on

event countExample code,

off line

Axon (Java/Scala)

Upcaster / UpcasterChain

Yes, triggers on event count

Yes, ReplayingCluster

Akka Persistence (Java/Scala)

Event Adapter Yes, decided by actor Yes

Page 55: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

QUESTIONS@michieltcs / [email protected]

www.touchdownconsulting.nl

https://joind.in/talk/584c0

Page 56: CQRS & Event Sourcing in the wild (ScotlandPHP 2016)

THANK YOU!@michieltcs / [email protected]

www.touchdownconsulting.nl

https://joind.in/talk/584c0