reactive applications using akka

Post on 08-Sep-2014

4.366 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

Basic intro to reactive applications concepts and a crash course on some of the tools Akka and some other providers give use

TRANSCRIPT

miguelinlas3@gmail.com - Liferay Inc and MadridJUG

@miguelinlas3

Miguel Ángel Pastor Olivar

Reactive ApplicationsBuilding concurrent and distributed apps using Akka

Saturday, October 19, 13

Writing software for the Liferay platform team

About me

Phd student? on distributed and cloud systems

Scala enthusiast

Twitter: @miguelinlas3

Saturday, October 19, 13

Reactive apps: do we really need them?

Crash course on basic Akka concepts

Old known problems

A quick look into newer (and more fun tools)

Agenda

Saturday, October 19, 13

Applications has become extremely demanding

New kind of systems

Event driven, scalable , resilient, responsive

This is what Reactive Applications are all about

Reactive applications

Saturday, October 19, 13

BlockingCaller blocked. Wait for the results

Non blockingCaller not blocked. Need to pool

AsynchronousCaller not blocked. Select, epoll, signals

Event drivenMessage flowing through the system

Reactive applications: definitions

Saturday, October 19, 13

Basic pillars

Saturday, October 19, 13

Basic pillars

Event Driven

Saturday, October 19, 13

Basic pillars

Event Driven

Resilient

Saturday, October 19, 13

Basic pillars

Event Driven

Resilient Scalable

Saturday, October 19, 13

Basic pillars

Event Driven

Responsive

Resilient Scalable

Saturday, October 19, 13

Going event driven

Old known problems,The actor model

Saturday, October 19, 13

Going Event Driven

Saturday, October 19, 13

Going Event Driven

Shared Memory

Saturday, October 19, 13

Going Event Driven

Shared Memory

Saturday, October 19, 13

Going Event Driven

Shared Memory

Thread 1

Saturday, October 19, 13

Going Event Driven

Shared Memory

Thread 1 Thread 2

Saturday, October 19, 13

Going Event Driven

Shared Memory

Thread 1 Thread 2

Saturday, October 19, 13

Going Event Driven

Shared Memory

Thread 1 Thread 2

Saturday, October 19, 13

Going Event Driven

Shared Memory

Thread 1 Thread 2

R/W

Saturday, October 19, 13

Going Event Driven

Shared Memory

Thread 1 Thread 2

R/WR/W

Saturday, October 19, 13

Going Event Driven

Shared Memory

Thread 1 Thread 2

R/WR/W AVOID IT!!

Saturday, October 19, 13

Going event driven: problems with locks

Saturday, October 19, 13

Going event driven: problems with locks

Composition

Saturday, October 19, 13

Going event driven: problems with locks

CompositionLocks don´t compose

Saturday, October 19, 13

Going event driven: problems with locks

Composition GranularityLocks don´t compose

Saturday, October 19, 13

Going event driven: problems with locks

Composition GranularityLocks don´t compose

Have I taken too few locks? Too many?

Saturday, October 19, 13

Going event driven: problems with locks

Composition Granularity

Encapsulation

Locks don´t compose

Have I taken too few locks? Too many?

Saturday, October 19, 13

Going event driven: problems with locks

Composition Granularity

Encapsulation

Locks don´t compose

Have I taken too few locks? Too many?

Breaking abstractions

Saturday, October 19, 13

Going event driven: problems with locks

Composition Granularity

EncapsulationCorrectness

Locks don´t compose

Have I taken too few locks? Too many?

Breaking abstractions

Saturday, October 19, 13

Going event driven: problems with locks

Composition Granularity

EncapsulationCorrectness

Locks don´t compose

Have I taken too few locks? Too many?

Have I taken the correct lock?

Breaking abstractions

Saturday, October 19, 13

Going event driven: problems with locks

Composition Granularity

EncapsulationCorrectness

Ordering

Locks don´t compose

Have I taken too few locks? Too many?

Have I taken the correct lock?

Breaking abstractions

Saturday, October 19, 13

Going event driven: problems with locks

Composition Granularity

EncapsulationCorrectness

Ordering

Locks don´t compose

Have I taken too few locks? Too many?

Have I taken the correct lock?

Have I used the correct order?

Breaking abstractions

Saturday, October 19, 13

Asynchronous message/event passing

Workflow of the events through your system

Benefits:Better throughputLower latenciesLoosely coupled solutions

Going event driven: designing your system

Saturday, October 19, 13

Going event driven: Amdahl’s law

Saturday, October 19, 13

Going event driven: the actor model

Fundamental unit of computation that embodies:• Processing• Storage• Communication

Three axioms. When an Actor receives a message it can:• Create new Actors• Send messages to Actors it knows• Designate how it should handle the next message it receives

Carl Hewitt

Saturday, October 19, 13

Going event driven: the actor model

Saturday, October 19, 13

Going event driven: the actor model

Saturday, October 19, 13

Going event driven: the actor model

Saturday, October 19, 13

Going event driven: the actor model

Zero sharing

Isolated, lightweight event based processes

Communication through asynchronous message passing

Location transparent

Built-in supervision

Saturday, October 19, 13

Actor model: Define a new actor

public class MetricsProcessorActor extends UntypedActor {

public void onReceive(Object message) { if (message instanceof JVMMetric) { JVMMetric jvmMetric = (JVMMetric)message;

_dataStore.save(jvmMetric); } }

private DataStore _dataStore = new LogDataStore();}

Saturday, October 19, 13

Actor model: Creating an actor

ActorSystem _agentSystem = ActorSystem.create("AgentSystem");

ActorRef metricsActor = _agentSystem.actorOf(

new Props(new UntypedActorFactory() { @Override public Actor create() {

return new MetricsActor(metricsActor);}

}),"metricsActor");

Saturday, October 19, 13

Actor model: Getting a reference

ActorSystem _agentSystem = ActorSystem.create("AgentSystem");

ActorRef handshakeActor = _agentSystem.actorFor(

"akka://MonitoringServiceSystem@localhost:5557/user/handshakeActor");

Saturday, October 19, 13

Actor model: Sending a message

metricsActor.tell(new JVMMessage("JVM-MemoryUsage", new Date().getTime()));

Saturday, October 19, 13

Actor model: Replying to a message

public class HandshakeActor extends UntypedActor {

public void onReceive(Object message) {

if (message instanceof AuthMessage) { AuthMessage authMessage = (AuthMessage)message;

if (authMessage.getUser() == "migue" && authMessage.getCredentials() == "migue")

getSender().tell("ok"); else

getSender().tell("fail"); } else throw new IllegalStateException("Unable to handle " +

message); }}

Saturday, October 19, 13

Actor model: Switching implementation

public class MetricsProcessorActor extends UntypedActor {

public void onReceive(Object message) { if (message instanceof SwappingMessage) { getContext().become(altPersistence, false) }

} Procedure<Object> altPersistence = new Procedure<Object>() { @Override public void apply(Object message) { altDatastore.save(message); }

DataStore altDatastore = new AltDataStore();};

private DataStore _dataStore = new LogDataStore();}

Saturday, October 19, 13

Actor model: Routing

final ActorSystem monitoringServiceSystem =ActorSystem.create("MonitoringServiceSystem");

ActorRef metricsActor = monitoringServiceSystem.actorOf(

new Props(MetricsProcessorActor.class).withRouter( new RoundRobinRouter(100), "metricsActor"); }

metricsActor.tell(new JVMMessage("JVM-MemoryUsage", new Date().getTime()));

Dealing with routers does not change our code

Saturday, October 19, 13

Actor model: Configuring a router

akka { actor { deployment { /metricsActor { router = round-robin nr-of-instances = 100 } } }}

Saturday, October 19, 13

Going scalable

Distributed computing,The actor model

Saturday, October 19, 13

Going scalable: scalability

I really do have an scalability problem ...

if my system is fast for a single user but slow when the system is under heavy load

Saturday, October 19, 13

Going scalable: transparent distributed computing

Distributed shared mutable state

Distributed objects

Distributed transactions

Saturday, October 19, 13

Going scalable: transparent distributed computing

Synchronous method dispatching across the network is a bad idea

Ignores partial failures

Raises Latency

General scalability and DC concerns

Saturday, October 19, 13

Going scalable: transparent distributed computing

EMBRACE THE NETWORK!!

Saturday, October 19, 13

Going scalable: remote actors

akka { actor { deployment { /metricsActor {

remote = "akka://monitorSystem@name:5557"

} } }}

final ActorSystem monitoringServiceSystem =ActorSystem.create("MonitoringServiceSystem");

ActorRef metricsActor = monitoringServiceSystem.actorOf( new Props(MetricsProcessorActor.class), "metricsActor");

No changes are required in our existing code!!

Saturday, October 19, 13

Going resilient

Error handling

Saturday, October 19, 13

Going resilient: common problems

Single thread of control

Thread blows up --> you are screwed

Error handling within single thread

Errors don´t get propagated

Defensive programmingTangled within business logicScattered along all our codebase

Saturday, October 19, 13

Going resilient: actor topology and supervision

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B5

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7

Saturday, October 19, 13

Supervision strategies: One for one

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B5

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7

Saturday, October 19, 13

Supervision strategies: One for one

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7

Saturday, October 19, 13

Supervision strategies: One for one

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7

Saturday, October 19, 13

Supervision strategies: One for one

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7

Saturday, October 19, 13

Supervision strategies: One for one

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7

Saturday, October 19, 13

Supervision strategies: One for one

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B5

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B6

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

B7

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B6

B7

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B6

Saturday, October 19, 13

Supervision strategies: One for all

System

A1

A2

A4

B1

B2

B4

B3

A3

/A1

/A1/A2

/A1/A2/A4

/A1/A3

/B1

/B1/B2

/B1/B2/B4

/B1/B3

/B1/B3/B5

/B1/B2/B6

/B1/B2/B7B5

B6

B7

Saturday, October 19, 13

Going resilient: configure supervision

final SupervisorStrategy supervisorStrategy = new OneForOneStrategy(

3, Duration.create(1, TimeUnit.MINUTES),new Class<?>[] {Exception.class});

_metricsActor = _cloudServiceSystem.actorOf( new Props(MetricsProcessorActor.class).

withRouter( new RoundRobinRouter(100).

withSupervisorStrategy( supervisorStrategy)),

"metricsActor");

Supervision strategies are pluggable and you can develop and configure your own

Saturday, October 19, 13

More tools

We deserve better and more fun tools

Saturday, October 19, 13

More tools: futures

•Spawn concurrent computations

•Write once - Read many

•Freely sharable

•Non-blocking composition

•Composable (monadic operations)

•Managing failure

Saturday, October 19, 13

More tools: futures

val f: Future[List[String]] = future { session.getRecentPosts}

// handle both cases: Success and Failuref onComplete { case Success(posts) => for (post <- posts) println(post) case Failure(t) => println("An error has occured: " +

t.getMessage)}

// only handle Successf onSuccess { case posts => for (post <- posts) println(post)}

// only handle Failuref onFailure { case t => println("An error has occured: " + t.getMessage)}

Saturday, October 19, 13

More tools: agents

•Reactive memory cells

•Send update function to an agent

•Reads are “free”

•Composable

•Originally in Clojure, borrowed by Akka

Saturday, October 19, 13

More tools: agents

// declare the agentval counter = Agent(0)

// send the function: enqueued the changecounter send { _ + 1}

// long running or blocking operations

implicit val ec = defineSomeExecutionContext()agent sendOff blockingOperation

// read the agent’ s valueval agentValue = counter.value

Saturday, October 19, 13

More tools: software transactional memory

Sometimes we will deal with shared stateHeap + Stack: transactional dataset:

Begin, commit, rollback

Retry on collision

Rollback on abort

Transaction composability

Saturday, October 19, 13

More tools: reactive extensions

•Futures + Stream concept

•Composables

•Async and event based

•Push collections

•JVM available through the RxJava project

Saturday, October 19, 13

More tools: reactive extensions

def simpleComposition() { customObservableNonBlocking() .skip(10) .take(5) .map({ stringValue -> return stringValue + "_transformed"}) .subscribe({ println "nextElement => " + it})} // we should an output like this

nextElement => foo_10_transformednextElement => foo_11_transformednextElement => foo_12_transformednextElement => foo_13_transformednextElement => foo_14_transformed

Saturday, October 19, 13

More tools: reactive extensions

def Observable<T> getData(int id) { if(availableInMemory) { return Observable.create({ observer -> observer.onNext(valueFromMemory); observer.onCompleted(); }) } else { return Observable.create({ observer -> executor.submit({ try { T value = getValueFromRemoteService(id); observer.onNext(value); observer.onCompleted(); }catch(Exception e) { observer.onError(e); } }) }); }}

Saturday, October 19, 13

Useful approaches

Where should I use each tool?

Saturday, October 19, 13

Layers of complexity

Declarative & immutable coreLogic or functional programmingFutures and/or dataflow

Non-determinism when neededActors, Agents or Rx

Shared mutabilityProtected by Software Transactional Memory

Finally, only if it is really neededLocks and explicit threads

Saturday, October 19, 13

Takeways

A quick summary

Saturday, October 19, 13

Takeaways

Go reactive

Avoid locking (share nothing, lock free algs)

Already in the JVM? Akka could be good choice

Distributed systems are hard

Use the correct level of abstraction

And remember ...

Saturday, October 19, 13

Takeaways

When all you have is a hammer everything looks like

a nail.

Choose the

right tool for your job!

Saturday, October 19, 13

Questions?

And let’s hope answers

Saturday, October 19, 13

References

Interesting resources

Saturday, October 19, 13

References: frameworks and toolkits

Cloud Haskell

NodeJS

Netty IO

Finagle

Saturday, October 19, 13

top related