0% found this document useful (0 votes)
57 views115 pages

Go Reactive: Event-Driven, Scalable, Resilient & Responsive Systems

The document discusses the need for new tools to build applications that can manage mobile devices, multicore architectures, and cloud computing environments, while delivering interactive, responsive, and collaborative experiences. It states that systems need to be event-driven, scalable, resilient, and responsive. The document introduces several new approaches for building such reactive systems, including actors, agents, futures/dataflow, and reactive extensions. These new approaches emphasize location transparency, asynchronous messaging, and avoiding shared mutable state.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
57 views115 pages

Go Reactive: Event-Driven, Scalable, Resilient & Responsive Systems

The document discusses the need for new tools to build applications that can manage mobile devices, multicore architectures, and cloud computing environments, while delivering interactive, responsive, and collaborative experiences. It states that systems need to be event-driven, scalable, resilient, and responsive. The document introduces several new approaches for building such reactive systems, including actors, agents, futures/dataflow, and reactive extensions. These new approaches emphasize location transparency, asynchronous messaging, and avoiding shared mutable state.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 115

Go Reactive

Event-Driven,
Scalable,
Resilient &
Responsive
Systems

Jonas Bonr
CTO Typesafe
@jboner

New Tools for a New Era


The demands and expectations for applications have
changed dramatically in recent years

New Tools for a New Era


The demands and expectations for applications have
changed dramatically in recent years
We need to write applications that manages
1. Mobile devices
2. Multicore architectures
3. Cloud computing environments

New Tools for a New Era


The demands and expectations for applications have
changed dramatically in recent years
We need to write applications that manages
1. Mobile devices
2. Multicore architectures
3. Cloud computing environments

Deliver applications that are


1. Interactive & Real-time
2. Responsive
3. Collaborative

New Tools for a New Era

New Tools for a New Era


We to need to build systems that:

New Tools for a New Era


We to need to build systems that:

react to events Event-Driven

New Tools for a New Era


We to need to build systems that:

react to events Event-Driven

react to load

Scalable

New Tools for a New Era


We to need to build systems that:

react to events Event-Driven

react to load

react to failure Resilient

Scalable

New Tools for a New Era


We to need to build systems that:

react to events Event-Driven

react to load

react to failure Resilient

react to users Responsive

Scalable

New Tools for a New Era


We to need to build systems that:

react to events Event-Driven

react to load

react to failure Resilient

react to users Responsive

Scalable

Reactive Applications

Reactive
Readily responsive to a stimulus

- Merriam Webster

The four traits of Reactive


Responsive

Scalable

Resilient

Event-Driven

Event-Driven
The flow of the program is determined by events

- Wikipedia

Shared mutable state

Shared mutable state


Together with threads...

Shared mutable state


Together with threads...

...leads to

Shared mutable state


Together with threads...
...code that is totally non-deterministic
...leads to

Shared mutable state


Together with threads...
...code that is totally non-deterministic
...leads to

...and the root of all EVIL

Shared mutable state


Together with threads...
...code that is totally non-deterministic
...leads to

...and the root of all EVIL

Please, avoid it at all cost

Shared mutable state


Together with threads...
...code that is totally non-deterministic
...leads to

...and the root of all EVIL

Please, avoid it at all cost

1. Never block

1. Never block
...unless you really have to
Blocking kills scalability (& performance)
Never sit on resources you dont use
Use non-blocking IO
Use lock-free concurrency

2. Go Async
Design for reactive event-driven systems

Use asynchronous event/message passing

Think in workflow, how the events flow in the system

Gives you
1. lower latency
2. better throughput
3. a more loosely coupled architecture, easier to
extend, evolve & maintain

Amdahls Law

Amdahls Law

e
b
o
t
s
d
e
e
N
m
o
r
f
e
v
i
t
c
a
e
M
R
O
T
T
O
B
o
t
P
O
T

You deserve better tools


Actors
Agents
Futures/Dataflow
Reactive Extensions (Rx)

Actors
ShareNOTHING
Isolated lightweight event-based processes
Each actor has a mailbox (message queue)
Communicates through asynchronous &
non-blocking message passing
Location transparent (distributable)
Supervision-based failure management
Examples: Akka & Erlang

Actors in Akka
public class Greeting implements Serializable {
public final String who;
public Greeting(String who) { this.who = who; }
}
!

public class GreetingActor extends UntypedActor {


!

public void onReceive(Object message) {


if (message instanceof Greeting)
println("Hello " + ((Greeting) message).who);
}
}

Actors in Akka
Define the message(s) the Actor
should be able to respond to

public class Greeting implements Serializable {


public final String who;
public Greeting(String who) { this.who = who; }
}
!

public class GreetingActor extends UntypedActor {


!

public void onReceive(Object message) {


if (message instanceof Greeting)
println("Hello " + ((Greeting) message).who);
}
}

Actors in Akka
Define the message(s) the Actor
should be able to respond to

public class Greeting implements Serializable {


public final String who;
public Greeting(String who) { this.who = who; }
Define the Actor class
}
!

public class GreetingActor extends UntypedActor {


!

public void onReceive(Object message) {


if (message instanceof Greeting)
println("Hello " + ((Greeting) message).who);
}
}

Actors in Akka
Define the message(s) the Actor
should be able to respond to

public class Greeting implements Serializable {


public final String who;
public Greeting(String who) { this.who = who; }
Define the Actor class
}
!

public class GreetingActor extends UntypedActor {


!

public void onReceive(Object message) {


if (message instanceof Greeting)
println("Hello " + ((Greeting) message).who);
}
Define the Actors behavior
}

Agents
Reactive memory cells
Send a update function to the Agent, which
1. adds it to an (ordered) queue, to be
2. applied to the Agent async & non-blocking

Reads are free, just dereferences the Ref


Composes nicely
Examples: Clojure & Akka

Agents in Akka

val agent = Agent(5)


agent send (x => x + 1)
agent send (x => x * 2)

Futures/Dataflow
Allows you to spawn concurrent computations
and work with the not yet computed results
Write-once, Read-many
Freely sharable
Allows non-blocking composition
Monadic (composes in for-comprehensions)
Build in model for managing failure

Futures in Scala
val result1 = future { ... }
val result2 = future { ... }
val result3 = future { ... }
!

val sum
r1 <r2 <r3 <} yield

= for {
result1
result2
result3
{ r1 + r2 + r3 }

Reactive Extensions (Rx)


Extend Futures with the concept of a Stream
Composable in a type-safe way
Event-based & asynchronous
Observable Push Collections
onNext(T), onError(E), onCompleted()
Compared to Iterable Pull Collections

Examples: Rx.NET, RxJava, RxJS etc.

RxJava

getDataFromNetwork()
.skip(10)
.take(5)
.map({ s -> return s + " transformed" })
.subscribe({ println "onNext => " + it })

Scalable
Capable of being easily expanded or upgraded on demand

- Merriam Webster

Distributed systems is the

new normal

Distributed systems is the

new normal
You already have a distributed system,
whether you want it or not

Distributed systems is the

new normal
You already have a distributed system,
whether you want it or not

Mobile
NOSQL DBs

SQL Replication
Cloud Services

What is the essence of


distributed computing?

What is the essence of


distributed computing?
Its to try to overcome that
1. Information travels at the speed of light
2. Independent things fail independently

Why do we need it?

Why do we need it?


Scalability
When you outgrow
the resources of
a single node

Why do we need it?


Scalability
When you outgrow
the resources of
a single node

Availability
Providing resilience if
one node fails

Why do we need it?


Scalability
When you outgrow
the resources of
a single node

Availability
Providing resilience if
one node fails

Rich stateful clients

The problem?

The problem?
It is still

Very Hard

No difference
Between a

Slow node
and a

Dead node

The network is
Inherently Unreliable

The network is
Inherently Unreliable
http://aphyr.com/posts/288-the-network-is-reliable

Fallacies
Peter
Deutschs
8 Fallacies
of
Distributed
Computing

Fallacies
Peter
Deutschs
8 Fallacies
of
Distributed
Computing

1. The network is reliable


2. Latency is zero
3. Bandwidth is infinite
4. The network is secure
5. Topology doesn't change
6. There is one administrator
7. Transport cost is zero
8. The network is homogeneous

Graveyard of distributed systems


Distributed Shared Mutable State
N

EVIL

(where N is number of nodes)

Graveyard of distributed systems


Distributed Shared Mutable State
N

EVIL

(where N is number of nodes)

Serializable Distributed Transactions

Graveyard of distributed systems


Distributed Shared Mutable State
N

EVIL

(where N is number of nodes)

Serializable Distributed Transactions


Synchronous RPC

Graveyard of distributed systems


Distributed Shared Mutable State
N

EVIL

(where N is number of nodes)

Serializable Distributed Transactions


Synchronous RPC
Guaranteed Delivery

Graveyard of distributed systems


Distributed Shared Mutable State
N

EVIL

(where N is number of nodes)

Serializable Distributed Transactions


Synchronous RPC
Guaranteed Delivery
Distributed Objects

Graveyard of distributed systems


Distributed Shared Mutable State
N

EVIL

(where N is number of nodes)

Serializable Distributed Transactions


Synchronous RPC
Guaranteed Delivery
Distributed Objects
Sucks like an inverted hurricane - Martin Fowler

Instead

Instead

Embrace the Network


Use
Asynchronous
Message
Passing

t
i
h

n
a

b
d

e
od n
e

t
i
w

We need

Location Transparency

What is
Location Transparency?
// send message to local actor
ActorRef localGreeter = system.actorOf(
new Props(GreetingActor.class), greeter");
!

localGreeter.tell(Jonas);

What is
Location Transparency?
// send message to local actor
ActorRef localGreeter = system.actorOf(
new Props(GreetingActor.class), greeter");
!

localGreeter.tell(Jonas);

// send message to remote actor


ActorRef remoteGreeter = system.actorOf(
new Props(GreetingActor.class), greeter");
!

remoteGreeter.tell(Jonas);

What is
Location Transparency?

e
c
n
e
r
e
f
f
i
d
o

// send message to local actor


ActorRef localGreeter = system.actorOf(
new Props(GreetingActor.class), greeter");
!

localGreeter.tell(Jonas);

// send message to remote actor


ActorRef remoteGreeter = system.actorOf(
new Props(GreetingActor.class), greeter");
!

remoteGreeter.tell(Jonas);

Divide & Conquer

Partition

for scale

Replicate
for resilience

Share
Nothing

Share
Nothing
Asynchronous
Communication

Share
Nothing
Asynchronous
Communication

Loose
Coupling

Share
Nothing
Asynchronous
Communication

Loose
Coupling
Location
Transparency

Share
Nothing
Asynchronous
Communication

Loose
Coupling
Location
Transparency

No limit to scalability

Share
Nothing
Asynchronous
Communication

Loose
Coupling
Location
Transparency

Close to at least

No limit to scalability

Resilience
The ability of a substance or object to spring back into shape.

The capacity to recover quickly from difficulties.

- Merriam Webster

Failure Recovery in Java/C/C# etc.

Failure Recovery in Java/C/C# etc.


You are given a SINGLE thread of control
If this thread blows up you are screwed
So you need to do all explicit error handling
WITHIN this single thread
To make things worse - errors do not
propagate between threads so there is NO
WAY OF EVEN FINDING OUT that something
have failed
This leads to DEFENSIVE programming with:
Error handling TANGLED with business logic
SCATTERED all over the code base

Failure Recovery in Java/C/C# etc.

o
d
n
a
c
e
W
!
!
!
R
E
T
T
E
B

You are given a SINGLE thread of control


If this thread blows up you are screwed

So you need to do all explicit error handling


WITHIN this single thread
To make things worse - errors do not
propagate between threads so there is NO
WAY OF EVEN FINDING OUT that something
have failed
This leads to DEFENSIVE programming with:
Error handling TANGLED with business logic
SCATTERED all over the code base

The Right Way

The Right Way


Isolate the failure
Compartmentalize
Manage failure locally
Avoid cascading failures

The Right Way


Isolate the failure
Compartmentalize
Manage failure locally
Avoid cascading failures

Use Bulkheads

...together with supervision

...together with supervision


1. Use Isolated lightweight processes (compartments)
2. Supervise these processes
1. Each process has a supervising parent process
2. Errors are reified and sent as (async) events to the supervisor
3. Supervisor manages the failure - can kill, restart, suspend/resume

Same semantics local as remote


Full decoupling between business logic & error handling
Build into the Actor model

Supervision in Akka
Every single actor has a
default supervisor strategy.
Which is usually sufficient.
But it can be overridden.

Supervision in Akka
Every single actor has a
default supervisor strategy.
Which is usually sufficient.
But it can be overridden.
class Supervisor extends UntypedActor {
private SupervisorStrategy strategy = new OneForOneStrategy(
10,
Duration.parse("1 minute"),
new Function<Throwable, Directive>() {
@Override public Directive apply(Throwable t) {
if (t instanceof ArithmeticException)
return resume();
else if (t instanceof NullPointerException) return restart();
else
return escalate();
}
});

@Override public SupervisorStrategy supervisorStrategy() {

Supervision in Akka
class Supervisor extends UntypedActor {
private SupervisorStrategy strategy = new OneForOneStrategy(
10,
Duration.parse("1 minute"),
new Function<Throwable, Directive>() {
@Override public Directive apply(Throwable t) {
if (t instanceof ArithmeticException)
return resume();
else if (t instanceof NullPointerException) return restart();
else
return escalate();
}
});

@Override public SupervisorStrategy supervisorStrategy() {


return strategy;
}
ActorRef worker = context.actorOf(new Props(Worker.class));

public void onReceive(Object message) throws Exception {


if (message instanceof Integer) worker.forward(message);
}

Responsive
Quick to respond or react appropriately

- Merriam Webster

Keep

latency consistent
1. Blue sky scenarios
2. Traffic bursts
3. Failures

Keep

latency consistent
1. Blue sky scenarios
2. Traffic bursts
3. Failures

The system should

always be responsive

Use Back Pressure


Bounded queues with backoff strategies

Use Back Pressure


Bounded queues with backoff strategies

Respect Littles Law:

L=W
Queue Length = Arrival Rate * Response Time

Use Back Pressure


Bounded queues with backoff strategies

Respect Littles Law:

L=W
Queue Length = Arrival Rate * Response Time
Response Time = Queue Length / Arrival Rate

Use Back Pressure


Bounded queues with backoff strategies

Respect Littles Law:

L=W
Queue Length = Arrival Rate * Response Time
Response Time = Queue Length / Arrival Rate

Use Back Pressure


Bounded queues with backoff strategies
Apply backpressure here

Respect Littles Law:

L=W
Queue Length = Arrival Rate * Response Time
Response Time = Queue Length / Arrival Rate

Smart Batching

Smart Batching
http://bit.ly/smartbatching
By Martin Thompson

Smart Batching

Smart Batching
http://bit.ly/smartbatching
By Martin Thompson

Reactive Web & Mobile Apps

Reactive Web & Mobile Apps


1. Reactive Request
Async & Non-blocking Request & Response

Reactive Web & Mobile Apps


1. Reactive Request
Async & Non-blocking Request & Response

2. Reactive Composition

Reactive Request + Reactive Request + ...

Reactive Web & Mobile Apps


1. Reactive Request
Async & Non-blocking Request & Response

2. Reactive Composition

Reactive Request + Reactive Request + ...

3. Reactive Push
Stream Producer

Reactive Web & Mobile Apps


1. Reactive Request
Async & Non-blocking Request & Response

2. Reactive Composition

Reactive Request + Reactive Request + ...

3. Reactive Push
Stream Producer

4. 2-way Reactive (Bi-Directional Reactive Push)

Reactive Web & Mobile Apps


1. Reactive Request
Async & Non-blocking Request & Response

2. Reactive Composition

Reactive Request + Reactive Request + ...

3. Reactive Push
Stream Producer

4. 2-way Reactive (Bi-Directional Reactive Push)

Reactive Web & Mobile Apps


1. Reactive Request
Async & Non-blocking Request & Response

2. Reactive Composition

Reactive Request + Reactive Request + ...

3. Reactive Push
Stream Producer

4. 2-way Reactive (Bi-Directional Reactive Push)


Enables Reactive UIs
1. Interactive
2. Data Synchronization
3. Real-time Collaboration

Reactive Composition in Play


public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
}

Reactive Composition in Play


public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
}

standard non-reactive request

Reactive Composition in Play


public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
}

standard non-reactive request


def get(symbol: String): Action[AnyContent] = Action.async {
for {
tweets
<- getTweets(symbol)
sentiments <- Future.sequence(loadSentiments(tweets.json))
} yield Ok(toJson(sentiments))
}

Reactive Composition in Play


public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
}

standard non-reactive request


def get(symbol: String): Action[AnyContent] = Action.async {
for {
tweets
<- getTweets(symbol)
sentiments <- Future.sequence(loadSentiments(tweets.json))
} yield Ok(toJson(sentiments))
}

fully reactive non-blocking request composition

http://typesafe.com/platform/getstarted

Demo time

http://typesafe.com/platform/getstarted

Responsive

Scalable

Resilient

Event-Driven

http://reactivemanifesto.org

Jonas Bonr
CTO Typesafe
Twitter: @jboner

Go Reactive
Email: [email protected]
Web:
typesafe.com
Twtr: @jboner

You might also like