Top Banner
Eventsourcing with PHP and MongoDB Data Analysis with events
99

Eventsourcing with PHP and MongoDB

Jul 14, 2015

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Eventsourcing with PHP and MongoDB

Eventsourcingwith%PHP%and%MongoDB

Data$Analysis$with$events

Page 2: Eventsourcing with PHP and MongoDB

Hello!

My#name#is#Jacopo&Nardiello

• Programmer,*currently*located*in*London

• I*care*about*code*quality

• If*it's*not*tested,*it*doesn't*exist.

If#you#want#to#follow#me#@jnardiello

Page 3: Eventsourcing with PHP and MongoDB

What%is%this%talk%about

Page 4: Eventsourcing with PHP and MongoDB

A"li%le"bit"of"context

Page 5: Eventsourcing with PHP and MongoDB

About&Onebip

Mobile'payments!pla%orm.Start,up!born!in!2005,!acquired!by!Neomobile!group!in!2011.!

Onebip'today:.'70'countries.'200+'carriers.'5'billions'registered'users

Page 6: Eventsourcing with PHP and MongoDB

It#all#started#with#a#MonolithLAMP%stack

Page 7: Eventsourcing with PHP and MongoDB

To#Distributed#Systemsself%contained-services-talking-via-REST

Page 8: Eventsourcing with PHP and MongoDB

Modern'ServicesFirst&class&modern&NoSQL&distributed&dbs

Page 9: Eventsourcing with PHP and MongoDB

But$the$Monolith$is$s)ll$there

Page 10: Eventsourcing with PHP and MongoDB

The$problem

A"repor'ng"horror"story

Page 11: Eventsourcing with PHP and MongoDB

We#need#three#new#reports!

—"Manager

Sure,&no&problem!

Page 12: Eventsourcing with PHP and MongoDB

Deal%with%the%legacy%SQL%Schema

Page 13: Eventsourcing with PHP and MongoDB
Page 14: Eventsourcing with PHP and MongoDB

Deal%with%MongoDB

Page 15: Eventsourcing with PHP and MongoDB

A"li%le"bit"of"queries"here,a"li%le"bit"of"map/reduce"there

Page 16: Eventsourcing with PHP and MongoDB

1"month"later...

Page 17: Eventsourcing with PHP and MongoDB

Reports(are(finally(ready!

Page 18: Eventsourcing with PHP and MongoDB

un#l...

Page 19: Eventsourcing with PHP and MongoDB

Your%queries%are%killing%produc2on!

—"SysAdmin

Page 20: Eventsourcing with PHP and MongoDB

Heavy&querying&op/miza/onNew$indexes

s"ll$not$enough

Page 21: Eventsourcing with PHP and MongoDB

Let's&re(use&data&from&other&reports(don't'do'that)

Page 22: Eventsourcing with PHP and MongoDB

DB#is#Ok,#reports#delivered.

Page 23: Eventsourcing with PHP and MongoDB

but$then...

Page 24: Eventsourcing with PHP and MongoDB

Huston,(we(have(a(problem.(Reports(are(not(consistent((with(other(

reports)—"business"guy

Page 25: Eventsourcing with PHP and MongoDB
Page 26: Eventsourcing with PHP and MongoDB

Mistakesweremade

Page 27: Eventsourcing with PHP and MongoDB

#1

Avoid&Mul*ple&sources&of&truthIt's%hard%to%compare%different%data%from%different%in%a%distributed%

system%spli7ed%across%mul8ple%domains

Page 28: Eventsourcing with PHP and MongoDB

#2

Ubiquitous)languageSame%words,%different%concepts%across%domains

Page 29: Eventsourcing with PHP and MongoDB

#3

Fault&tolerance&to&changeChanging'a'report'shouldn't'have'side'effects

Page 30: Eventsourcing with PHP and MongoDB

Most%common%solu+ons

Page 31: Eventsourcing with PHP and MongoDB

#1

ETL$+$Map/Reduce

Page 32: Eventsourcing with PHP and MongoDB

#2

DWH$+$Consultants

Page 33: Eventsourcing with PHP and MongoDB

#3#Mad#science(Yeppa!)

Page 34: Eventsourcing with PHP and MongoDB

What%we%wanted

Page 35: Eventsourcing with PHP and MongoDB

Must%haveNo#down'me#in#produc'on

Consistent(across(domains

Page 36: Eventsourcing with PHP and MongoDB

Nice%to%haveA"system"elas*c"enough"to"extract"any"metric

Real%me'data

Page 37: Eventsourcing with PHP and MongoDB

In#DDD#we#found#the#light

Page 38: Eventsourcing with PHP and MongoDB

Eventsourcing-&-CQRS

Page 39: Eventsourcing with PHP and MongoDB

Eventsourcing

The$fundamental$idea$of$Event$Sourcing$is$that$of$ensuring(every(change(to(the(state(of(an(applica3on(is(captured(in(an(event(object,$and$that$these$event$objects$are$themselves$stored(in(the(sequence(

they(were(applied

—(Mar3n(Fowler

Page 40: Eventsourcing with PHP and MongoDB

Unrolling(a(stream(of(eventsStar%ng(from(the(beginning(of(%me,(you(are(

literally(unrolling(history(to(reach(the(state(in(a(given(%me

Page 41: Eventsourcing with PHP and MongoDB

Idea%#1

Every&change&to&the&state&of&your&applica4on&is&captured&in&an&event&object

"User%Logged%In",#"Payment%Sent",#"User%Landed"

Page 42: Eventsourcing with PHP and MongoDB

Idea%#2

Events'are'stored'in'the'sequence'they'were'applied'inside'an'eventstore

Page 43: Eventsourcing with PHP and MongoDB

Command'Query'Responsibility'Segrega6on

(CQRS)

Page 44: Eventsourcing with PHP and MongoDB
Page 45: Eventsourcing with PHP and MongoDB

Commands

Anything(that(happens(in(one(of(your(domains(is(triggered(by(a(command(and(generate(one(or(more(events.

Order received --> payment sent --> Items queued --> Confirmation email sent

Page 46: Eventsourcing with PHP and MongoDB

Idea%#3

Everything+is+an+event.+No+more+state.

Page 47: Eventsourcing with PHP and MongoDB

Query

Generate'read'models'from'events'depending'how'data'needs'to'be'actually'used'(by'users'and'other'applica9on'internals)

Page 48: Eventsourcing with PHP and MongoDB

Idea%#4

One$way$to$store$data/events$but$poten2ally$infinite$ways$to$read$them

A"prac'cal"example

Tech%ops,%Business%control,%Monitoring,%Accoun4ng%they%are%all%interested%in%reading%data%from%different%views.

Page 49: Eventsourcing with PHP and MongoDB

Healthy(NoSQL

Page 50: Eventsourcing with PHP and MongoDB

You$start$with$this

{ "_id": ObjectId("123"), "username": "Flash", "city": …, "phone": …, "email": …,}

Page 51: Eventsourcing with PHP and MongoDB

The$more$successful$your$company$is,$the$more$people

...The$more$people,$the$more$views

Page 52: Eventsourcing with PHP and MongoDB

With%documental%dbs%it's%magically%easy%to%add%new%fields%to%your%collec7ons.

Page 53: Eventsourcing with PHP and MongoDB

Soon$you$might$end$up$with

{ "_id": ObjectId("123"), "username": "Flash", "city": …, "phone": …, "email": …, "created_at": …, "updated_at": …, "ever_tried_to_purchase_something": …, "canceled_at": …, "acquisition_channel": …, "terminated_at": …, "latest_purchase_date": …, …}

Page 54: Eventsourcing with PHP and MongoDB

A"bomb"wai)ng"to"detonate

It's%impossible%to%keep%adding%state%changes%to%your%documents%and%then%expect%to%be%able%to%extract%them%with%a%single%query.

Page 55: Eventsourcing with PHP and MongoDB

Exploring*Tools

Page 56: Eventsourcing with PHP and MongoDB

EventStore• Engineered)for)event)sourcing

• Supports)projec4ons

• By)the)father)of)CQRS

• Great)performances

The$badWin$Only.$Run$on$*nix$with$Mono,$s4ll$too$unstable.

Page 57: Eventsourcing with PHP and MongoDB

LevelWHEN)

An#eventstore#built#with#Node.js#and#LevelDB8#Faster#than#light8#Completely#custom,#no#tool#to#handle#aggregates

Page 58: Eventsourcing with PHP and MongoDB

The$known$path

• PHP$(any$other$language$would$just$do$fine)

• MongoDB$2.x

Page 59: Eventsourcing with PHP and MongoDB

Why$MongoDBEvents'are'not'rela,onal

Scales'Well

Awesome'aggrega+on'framework

Page 60: Eventsourcing with PHP and MongoDB

Hands&on

Page 61: Eventsourcing with PHP and MongoDB

Storing(Events

Page 62: Eventsourcing with PHP and MongoDB

The$write$architecture

Service | \ | \ [event payload] | \ | Service --- Queue System <------------> API -> MongoDB / | / [event payload] | / |Service |

Page 63: Eventsourcing with PHP and MongoDB

Queues

Page 64: Eventsourcing with PHP and MongoDB

MongoDB'RS

A"mongod"replica*set"with"two"logical"dbs."1."Eventstore"DB"where"we"would"store"2."Repor=ng"DB"where"we"would"store"aggregates"and"final"reports

Page 65: Eventsourcing with PHP and MongoDB

Anatomy(of(an(event

{ '_id' : '3318c11e-fe60-4c80-a2b2-7add681492d9', 'type': 'an-event-type', 'data': { 'meta' : { … }, 'payload' : { … } }}

Storing(events

Page 66: Eventsourcing with PHP and MongoDB

Anatomy(of(an(event

'meta' : { 'creation_date': ISODate("2014-21-11T00:00:01Z"), 'saved_date': ISODate("2014-21-11T00:00:02Z"), 'source': 'some-bounded-context', 'correlation_id': 'a-correlation-id'},'payload' : { 'user_id': '1234', 'animal': 'unicorn', 'colour': 'pink', 'purchase_date': ISODate("2014-21-11T00:00:00Z"), 'price': '20\fantaueros'}

Storing(events

Page 67: Eventsourcing with PHP and MongoDB

Don't&trust&the&network:&Idempotence{ '_id' : '3318c11e-fe60-4c80-a2b2-7add681492d9', …}

The$_id$field$is$actually$defined$client0side$and$ensures$idempotence$if$an$event$is$received$two$8mes.

Page 68: Eventsourcing with PHP and MongoDB

Indexes• Events(collec,ons(are(HUGE((~100M*N(documents)

• Use(indexes(wisely(as(they(are(necessary(yet(expensive(

• With(suggested(events(structure:(type + data.meta.created_at

Page 69: Eventsourcing with PHP and MongoDB

BenchmarkingHow$many$events/second$can$you$store?

Our$machines$were$able$to$store$roughly$150$events/sec.$This$number$can$be$greatly$increased$with$dedicated$IOPS,$more$aggressive$inser@ng$policies,$etc..

Page 70: Eventsourcing with PHP and MongoDB

Final&Tips• Use%SSDs%on%your%storage%machines

• Pay%a5en6on%to%write%concerns

Page 71: Eventsourcing with PHP and MongoDB

From%Events%to%Meaningful%Metrics

Page 72: Eventsourcing with PHP and MongoDB

The$Event$Processing$Pipeline

Sequential Projector -> Event Mapper -> Projection -> Aggregation

Page 73: Eventsourcing with PHP and MongoDB

A"real"life"problem

What%is%the%conversion%rate%of%our%registered%users?

Page 74: Eventsourcing with PHP and MongoDB

#1#The#registra-on#event{ '_id' : '3318c11e-fe60-4c80-a2b2-7add681492d9', 'type': 'user-registered', 'data': { 'meta' : { 'save_date': ISODate("2014-21-11T00:00:09Z"), 'created_at': ISODate("2014-21-11T00:00:01Z"), 'source': 'core-domain', 'correlation_id': 'user-123456' }, 'payload' : { 'user_id': 123, 'username': 'flash', 'email': '[email protected]', 'country': 'IT' } }}

Page 75: Eventsourcing with PHP and MongoDB

#2#The#purchase#event{ '_id' : '3318c11e-fe60-4c80-a2b2-7add681492d9', 'type': 'user-purchased', 'data': { 'meta' : { 'save_date': ISODate("2014-21-11T00:10:09Z"), 'created_at': ISODate("2014-21-11T00:10:01Z"), 'source': 'payment-gateway', 'correlation_id': 'user-123456' }, 'payload' : { 'user_id': 123, 'email': '[email protected]', 'amount': 20, 'value': EUR, 'payment': 'credit_card', 'item': 'fluffy cat' } }}

Page 76: Eventsourcing with PHP and MongoDB

Sequen&al)projector)(1)

Divides'the'stream'of'events'into'batches,'filters'events'by'type'and'pass'those'of'interest'to'the'mapper'

[]->[x]->[]->[x]->[]->[]->[]->[] |--------------| |------------| | | | | ---> Projector

Page 77: Eventsourcing with PHP and MongoDB

Sequen&al)projector)(2)• It's&a&good&idea&to&select&fixed&sizes&batches&to&avoid&memory&problems&when&you&load&your&Cursor&in&memory

• Could&be&a&long=running&process&selec>ng&events&as&they&arrive&in&real%me

Page 78: Eventsourcing with PHP and MongoDB

Event&Mapper&(1)

Translates)event)fields)to)the)Read)Model)domain.

Takes&an&event&as&input,&applies&a&bunch&of&logic&and&will&return&a&list&of&Read&Model&fields.

Page 79: Eventsourcing with PHP and MongoDB

Event&Mapper&(2)

Input&Event:&

user-registered

Output:

$output = [ 'user_id' => 123, // simply copied 'user_name' => 'flash', // simply copied 'email' => '[email protected]', // simply copied 'registered_at' => "2014-21-11T00:00:01Z" // From the data.meta.created_at event field ];

Page 80: Eventsourcing with PHP and MongoDB

Event&Mapper&(3)

Input&Event:&

user-purchased

Output:

$output = [ 'user_id' => 123, // simply copied 'email' => '[email protected]', // simply copied 'purchased_at': "2014-21-11T00:10:01Z" // From the data.meta.created_at event field ];

Page 81: Eventsourcing with PHP and MongoDB

Projec'on)(1)

Essen%ally)it)is)your)read)model.)The$data$that$the$business$is$interested$in.

Page 82: Eventsourcing with PHP and MongoDB

The$Projec*on$,$a.er$event#1$(2)

db.users_conversion_rate_projection.findOne()

{ 'user_id': 123, 'user_name': 'flash', 'email': '[email protected]', 'registered_at': "2014-21-11T00:00:01Z"}

Page 83: Eventsourcing with PHP and MongoDB

The$Projec*on$,$a.er$event#2$(3){ 'user_id': 123, 'user_name': 'flash', 'email': '[email protected]', 'registered_at': "2014-21-11", 'purchased_at': "2014-21-11" // Added this field and rewrote others}

Page 84: Eventsourcing with PHP and MongoDB

The$Projec*on$,$collec*on{ 'user_id': 123, 'user_name': 'flash', 'email': '[email protected]', 'registered_at': "2014-21-11", 'purchased_at': "2014-21-11" // Added this field and rewrote others}{ 'user_id': 456, 'user_name': 'batman', 'email': '[email protected]', 'registered_at': "2014-21-11", 'purchased_at': "2014-21-11" // Added this field and rewrote others}{ 'user_id': 789, 'user_name': 'superman', 'email': '[email protected]', 'registered_at': "2014-21-12", 'purchased_at': "2014-21-12" // Added this field and rewrote others}

Page 85: Eventsourcing with PHP and MongoDB

The$Projec*on$,$A$few$thoughts$(4)

Note%that%we%didn't%copy%from%events%to%projec6on%all%the%available%fields.%Just%relevant%ones.

Page 86: Eventsourcing with PHP and MongoDB

From%these%two%events%we%could%have%generated%infinite%read%models%such%as:

• List&all&purchased&products&and&related&amounts&for&the&company&buyers&

• Map&all&sales&and&revenues&for&our&accoun8ng&dept

• List&transac8ons&for&the&financial&department

Page 87: Eventsourcing with PHP and MongoDB

One$way$to$write,$infinite$ways$to$read!

Page 88: Eventsourcing with PHP and MongoDB

The$aggrega(on$(1)$.$Total$registered$usersvar registered = db.users_conversion_rate_projection.aggregate([ { $match: { "registered_at": { $gte: ISODate("2015-11-21"), $lte: ISODate("2015-11-22") } } }, { $group: { _id: { }, count: { $sum:1 } } }]);

Page 89: Eventsourcing with PHP and MongoDB

The$aggrega(on$(2)$.$Users$with$a$purchasevar purchased = db.users_conversion_rate_projection.aggregate([ { $match: { "registered_at": { $gte: ISODate("2015-11-21"), $lte: ISODate("2015-11-22") }, "purchased_at": { $exists: true } } }, { $group: { _id: { }, count: { $sum:1 } } }]);

Page 90: Eventsourcing with PHP and MongoDB

The$aggrega(on$(3)$.$Automate$all$the$things• You%can%easily%create%the%aggrega2on%framework%statement%by%composi2on%abstrac2ng%the%concept%of%Column.

• This%way%you%can%dynamically%aggregate%your%projec2ons%on%(for%example)%an%API%requests.

• If%your%Projector%is%a%long%running%process,%your%projec2ons%will%be%updated%to%the%second%and%you%automagically%get%real%me%data.

Page 91: Eventsourcing with PHP and MongoDB

Another(events(usage:(Business(&(Tech(Monitoring

Page 92: Eventsourcing with PHP and MongoDB

Beware&of&the&beast!No#Silver#Bullet

Page 93: Eventsourcing with PHP and MongoDB

Events'are'expensiveRequire'a'lot'of'TIME'to'be'parsed

Page 94: Eventsourcing with PHP and MongoDB

Events'are'expensiveYou$will$end$up$with$this$billion$size$collec2on$

(and$coun2ng).

Page 95: Eventsourcing with PHP and MongoDB

Fixing&wrong&events&is&painful

Page 96: Eventsourcing with PHP and MongoDB

Events'are'complex

Page 97: Eventsourcing with PHP and MongoDB

Moving'around'events'is'horribly'painful

Page 98: Eventsourcing with PHP and MongoDB

Mongo%won't%help%you.Actually(it(will(make(your(life(incredibly(difficult(with(hidden(bugs(and(leaking(

documenta8on.

Page 99: Eventsourcing with PHP and MongoDB

Thank&you!@jnardiello