Codemotion akka persistence, cqrs%2 fes y otras siglas del montón

73
MADRID · NOV 18-19 · 2016 Scala Programming @ Madrid Akka persistence, CQRS/ES y otras siglas del montón Javier Santos

Transcript of Codemotion akka persistence, cqrs%2 fes y otras siglas del montón

Page 1: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence, CQRS/ES y otras siglas del montón

Javier Santos

Page 2: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

About us

Javier Santos @jpaniego

«Hay dos formas de programar sin errores; sólo la tercera funciona»

Alan J Perlis

Page 3: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

scalera.es

@scalerablog

About us

Page 4: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem to solve

Page 5: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem to solve

Page 6: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem to solve

Page 7: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

DDD - Domain Driven Design● Context - The setting in which a word or statement appears that

determines its meaning

● Domain (Ontology) - The subject area to which the user applies a program is the domain of the software

● Model - A system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain

● Ubiquitous language - A language structured around the domain model and used by all team members to connect all the activities of the team with the software

Page 8: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

DDD - Domain Driven Design● Context - The setting in which a word or statement appears that

determines its meaning

● Domain (Ontology) - The subject area to which the user applies a program is the domain of the software

● Model - A system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain

● Ubiquitous language - A language structured around the domain model and used by all team members to connect all the activities of the team with the software

Page 9: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

DDD - Domain Driven Design● Context - The setting in which a word or statement appears that

determines its meaning

● Domain (Ontology) - The subject area to which the user applies a program is the domain of the software

● Model - A system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain

● Ubiquitous language - A language structured around the domain model and used by all team members to connect all the activities of the team with the software

Page 10: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Our domain modelcase class User( name: String, address: Address, credit: Double, currentBike: Option[Id[Bike]])

case class Bike( model: String, battery: Bike.Battery.Status, bikeStation: Option[Id[Station]])

case class Address( street: String, number: String, zipCode: String)

case class Station( address: Address, maxBikeCapacity: Int, currentCapacity: Int)

Page 11: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Anemic Domain Model

Page 12: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Anemic Domain Model

● Think about a domain class that only contains fields and no methods.

● Anti-pattern against the main idea of the object-oriented programming paradigm: combining data and process together.

● Why not using C structs then? ¬¬

Page 13: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Anemic Domain Modelcase class User( name: String, address: Address, credit: Double, currentBike: Option[Id[Bike]]) {

def startRental(bike: Id[Bike]): User = { require( currentBike.isEmpty,"There's another rental on course.") require( credit > 0, "Not enough credit to start a rental.") this.copy(currentBike = Some(bike)) }

//...

Page 14: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Anemic Domain Model //...

def finishRental(creditExpense: Double): User = { require( currentBike.isDefined, "There is not a rental on course.") this.copy( currentBike = None, credit = credit - creditExpense) }

}

Page 15: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Aggregate

● Cluster of domain objects

● The whole block of domain objects works as a sole entity.

User Bike

Address

Page 16: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Aggregate

trait Aggregate extends ...{def id: Id[This]

}

case class Station( address: Address, maxBikeCapacity: Int, currentCapacity: Int)

Page 17: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Event Sourcing● “Every change to the state of an application is captured in an event

object, and that these event objects are themselves stored in the sequence they were applied for the same lifetime as the application state itself” - Martin Fowler

Page 18: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Event Sourcing● The system state is the sum of the events

Page 19: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Stateful[T]trait Stateful[S] {

type This <: Stateful[S]

type Action = scalaz.State[S, Event]

val state: S

def apply(s: S): This

def update(f: Action): (This, E) = {val (newState, e) = f(state)(apply(newState), e)

}

}

Page 20: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

scalaz.State

Page 21: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

scalaz.State● Represents a state mutation that may generate some effect.

● type State[S, Effect] = StateT[Id, S, Effect]

● Monad = composable!

Page 22: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

scalaz.State

type Action[E] = scalaz.State[User, E]

def addCredit(amount: Double): Action[Double] = State(user =>

(user.copy(credit = user.credit + amount), amount))

def rentBike(bike: Id[Bike], timesUsed: Long): Action[Long] = State(user =>

(user.copy(currentBike = Some(bike), timesUsed + 1))

Page 23: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

scalaz.State

val topUpAndRent: Action[(Double, Long)] = for {

newCredit <- addCredit(10)timesUsed <- rentBike(Id(“bike-1”))

} yield (newCredit, timesUsed)

val (relaxingAnn, (newCredit, bikeAge)) = topUpAndRent(User(“Ann Bottle”, Addres(...), 0.0, None)

Page 24: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Immutability perversion

Page 25: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

StatefulAgg[T]trait StateAgg[S] extends Stateful[S]{

_: PersistenActor =>

var aggState: S

def updateState(f: Action): Unit = {val (newAgg, _) = update(f)aggState = newAgg.state

}

}

Page 26: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

StatefulAgg[T]trait StateAgg[S] extends Stateful[S]{

_: PersistenActor =>

var aggState: S

def updateState(f: Action): Unit = {val (newAgg, _) = update(f)aggState = newAgg.state

}

}

Page 27: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Page 28: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

CQRS

● Command Query Responsibility Segregation

● Main idea: “You can use a different model to update the information than the model you use to read information”

Page 29: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

CQRS

Page 30: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

CQRS

trait Command[Agg] {val to: Id[Agg]

}

trait Event

Page 31: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence● End of 2013

● Martin Krasser

● Main idea : store the internal state of an actor

● ...BUT not directly, only through the changes the actor has suffered.

Page 32: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence

Page 33: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence

Page 34: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence - Failure recovery

Page 35: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence - Failure recovery

Page 36: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence - Failure recovery

Page 37: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence - Failure recovery

Page 38: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Snapshotting

Page 39: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Snapshotting

Page 40: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Persistent actors

trait PersistenceStuff extends PersistentActor{

def persistenceId: String

def receiveCommand: Receive

def receiveRecover: Receive

}

Page 41: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

trait Reactive { _: Stateful[S] =>

val onEvent: Event => Action

val onSnapshot: Any => Action = {case snapshot => State(s => (s, snapshot))

}

def asEvent(c: Command[This]): Event

}

Persistent actors

Page 42: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

trait Aggregate[S] extends StateAgg[S] with Reactive with PersistentActor {def persistenceId: String = id.iddef receiveRecover: Receive = {

case event: Event => update(onEvent(event))case snapshot => update(onSnapshot(snapshot))

}def receiveCommand: Receive = {

case cmd: Command[This@unchecked] =>if (checkState(cmd))

persistAll(List(asEvent(cmd))){ event =>update(onEvent(event))sender ! event

}else sender ! Nope

}}

Persistent actors

Page 43: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

case class UserAgg(state: User.Default) extends Aggregate[User] {

type This = UserAggdef apply(s: User) = UserAgg(s)

override val onEvent = {case e@AddedCredit(amount) =>

State(s => (s.copy(credit = s.credit+10),e))}

def asEvent(c: Command[This]): Event = c match {case AddCredit(_, amount) => AddedCredit(amount)

}

}

Persistent actors

boilerplate

Page 44: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Persistence Queries● Like a PersistentActor but with no Command part

● peristenceId subscription or by tag

● refreshInterval in most plugins

Page 45: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Persistence Queriesval readJournal =

PersistenceQuery(system).readJournalFor[MyScaladslReadJournal]("akka.persistence.query.my-read-journal")

// issue query to journalval source: Source[EventEnvelope, NotUsed] =

readJournal.eventsByPersistenceId("user-1337")

// materialize stream, consuming eventsimplicit val mat = ActorMaterializer()source.runForeach { event => println("Event: " + event) }

Page 46: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

getOrCreate● A new command is launched against user1...how to deliver it?

● Managers

class UserManager extends Actor {override def receive = {

case cmd: Command[User@unchecked] =>getOrCreate(cmd.addresse) forward cmd

}}

Page 47: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

getOrCreate

● Imagine there are 500k registered users …

● ...you create a persistent actor and deliver the just arrived command…

● ...the actor keeps alive….

Page 48: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

getOrCreate

Page 49: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Passivation

● Kill the actor if it’s iddle…

trait Passivation extends PersistentActor {import ShardRegion.Passivatecontext.setReceiveTimeout(60.seconds)override def receiveCommand = {

//…case ReceiveTimeout =>

context.parent ! Passivate(stopMessage = Stop)}

}

Page 50: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Page 51: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Journal● Different supported pluggable storages:

○ AndroidSQLite○ BDB○ Cassandra○ Kafka○ DynamoDB○ HBase○ MongoDB○ …

● Why choosing a distributed database as Journal for High Availability?

Page 52: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

HA : Clustering

Page 53: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

HA : Clustering● Send semantics

○ Send: The message is sent to an only cluster actor that fits in the path. If several, the actor is chosen randomly.

clusterClient ! Send(«/user/handler», «hello», localAffinity = true)

○ SendToAll: The message is sent to all cluster actors that fit in the path.

clusterClient ! SendToAll(«/user/handler», «hi»)

○ Publish: The message is sent to all topic subscribers

clusterClient ! Publish(«myTopic», «hello»)

Page 54: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Partitioning : Sharding● Study case:

○ A command is sent (in a cluster) to aggregate1, the actor is created in node1, the command is processed.

○ A second command is sent (in the same cluster) to aggregate1, but this time the command is received by node2, so the actor is created there.

Page 55: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Partitioning : Sharding● It provides

○ Load balancing: In case a new is added to the cluster or another one crashes, the total actor amount is balanced.

○ Unique actor identification, so messages that are sent to the same actor will be forwarded to the node that handles in that moment that shard id (previous case won’t take place)

Page 56: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Partitioning : Sharding

● Semantics

○ Entry: It represents a uniquely identified entity with persistent state (Aggregate).

○ Shard: Entry group. Experts recommend

ShardAmount = 10 x MaxNodeAmount

○ ShardRegion: Same Entry shard group.

Page 57: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Partitioning : Sharding

Page 58: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

#graciasCarmena#llevameEnTuBiciceta

Page 59: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: eventual consistency● Changes may take

some time

● If the user requires an immediate update, user views could be updated when the command part has acknowledge the event persistence (handle it carefully...)

Page 60: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: Distributed transactions

● Let’s suppose credit transfer is allowed among users

● Saga Pattern: A persistent actor that represents a transaction among aggregates

Page 61: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: Distributed transactions

Page 62: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: cluster initialization

Page 63: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: cluster initialization

Page 64: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: cluster initialization

Page 65: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: cluster initialization

Page 66: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: Testing a PersistentActor

TestActorRef + PersistentActor =

Page 67: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem: Testing a PersistentActor

TestActorRef + PersistentActor =

Page 68: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Problem : Schema evolution● Imagine the following:

case class User(name: String, address: Address, amount: Double)

case class User(cardId: String, amount: Double, usualBike: Bike)

● Choosing proper serializers are the key (ProtoBuf, Avro, Java ser...no way)

● Event migration (EventAdapter)● How to:

○ add attribute○ remove attribute○ rename attribute○ ...

Page 69: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Lightbend approach

● Runs on JRE 1.8

● Multiple service control

● Event stream abstraction

● Easy scalability

● Java SDK ...

Page 70: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Lightbend approach

● Runs on JRE 1.8

● Multiple service control

● Event stream abstraction

● Easy scalability

● Java SDK ...

Page 71: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

scalera.es

@scalerablog

Page 72: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Page 73: Codemotion   akka persistence, cqrs%2 fes y otras siglas del montón

MADRID · NOV 18-19 · 2016

Scala Programming @ Madrid

Akka persistence, CQRS/ES y otras siglas del montón

Javier Santos