&√

Deputy CTO

Functional Programming
Composing Actors
&
Functional Programming
without sacrificing
Communication
Resilience
√

Deputy CTO

4
Connectedness
«Software is becoming
increasingly interconnected»
5
Klang’s Conjecture
«If you cannot solve a problem without programming;
you cannot solve a problem with programming.»
Reality Imaginary
>
My office door
7
Stunning views
Reality
• separation in space & time gives us
• communication for coordination
• variable delays
• partial failures
• only partial/local/stale knowledge
• systems
8
9
system
«a set of things working together as parts of
a mechanism or an interconnecting network;

a complex whole»
noun
Systems
• Purpose is typically simple
• Complex inner workings
• Consist of collaborating components
• Components can be systems themselves
• Components are as simple as feasible,
but not simpler
10
11
Resilience
«Any sufficiently complex system is always
running in degraded mode»
— Richard I. Cook, MD “How complex systems fail” (paraphrased)
Communication
• The production and consumption of messages
• Messaging implies that we need to be able to
address recipients
• Addresses/Identities are important
• They are knowledge that can be shared
• Messages can become delayed, lost 

or misunderstood
12
Think: Reliability
• Are we ever guaranteed delivery?
• at-most-once
• at-least-once
• exactly-once
• It’s not about guarantees,

it’s about reliability
13
Two-Phased Commit
14
Burstiness
• Most communication is bursty
• some is predictable
• some is unpredictable
• load shedding can cause burstiness
15
Flow control / Back pressure
16
• Buffers are only grease between cogs
• Does not solve overload problems
• Load shedding does not inform sender
• Reasons
• When shedding will end
www.reactive-­‐streams.org
Resilience
• Never assume that other entities are immortal
• Treat expectation violations as failures
• Always have a Plan B
• Clients are not responsible to fix a faulty provider
• Fail fast & predictably
17
18
Supervision
• Responsibility to deal with the failure/corruption of other
• Does not place the burden of fixing it on the collaborators
«Quis custodiet ipsos custodes?»
— Decimus Iunius Iuvenalis
19
actors
• Akka's unit of computation is called an actor
• Akka actors are purely reactive components:
• Current behavior
• Address
• Local storage
• Mailbox
• Scheduled to execute when sent a message
• An actor has a parent actor, handling its failures
• An actor may have 0..N child actors
20
« 2500 nodes × millions of actors per GB RAM = a lot»
actors
• An actor processes a message at a time
• Multiple-producers & Single-consumer
• The overhead per actor is about ~450bytes
• Run millions of actors on commodity hardware
• Akka Cluster currently handles ~2500 nodes
actors
21
actors
• Great for
• Communication
• Location transparency
• Elasticity
• Resilience
• Main challenge
• Composition
Functional Composition
a → b → c
23
Functional Programming
• Great for
• Composition
• Main challenge
• Communication
• Resilience
24
typed: On the horizon
• Project Gålbma
• distill an Actor to its essence: the Behavior
• everything is a message—for real this time
• remove the danger to close over Actor environment
• behavior composition
• completely pure Actor implementation,

through a process algebra (inspired by JoinCalculus)
Behavior is King
25
abstract class Behavior[T] {
def management(ctx: ActorContext[T], msg: Signal): Behavior[T]
def message(ctx: ActorContext[T], msg: T): Behavior[T]
def narrow[U <: T]: Behavior[U] = this.asInstanceOf[Behavior[U]]
}
Behavior example
26
object Server {
sealed trait Command
case class Get(id: Int)(val replyTo: ActorRef[Got]) extends Command
case class Put(name: String, ref: ActorRef[OtherCommand]) extends Command
case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]])
val initial: Behavior[Command] = withMap(Map.empty)
private def withMap(map: Map[String, ActorRef[OtherCommand]]) =
Total[Command] {
case g @ Get(id) =>
g.replyTo ! Got(id, Map.empty)
Same
case Put(name, ref) =>
withMap(map.updated(name, ref))
}
}
Most common dev task?
• Receive inputs
• Transform data
• Produce outputs
• Drink coffee
27
28
#undef STREAMS #define STREAMS
• ephemeral, time-dependent, sequences of elements
• possibly unbounded in length
• in essence: transformation & transportation of data
«No man ever steps in the same river twice,
for it's not the same river
and he's not the same man.»
— Heraclitus
streams
i m m u t a b l e
REUSABLE
c o m p o s a b l e
c o o r d i n a t e d

asynchronous

transformations
Getting data across
an asynchronous
b o u n d a r y
Getting data across
an asynchronous
b o u n d a r y

with non-blocking

back pressure
Reactive
Streams
Initiative
T
H
E
38
Requirements Push Pull
support potentially unbounded sequences 😃 😃
sender runs separately from receiver 😃 😃
rate of reception may vary from rate of sending 😃 😃
dropping elements should be a choice and not a necessity 💩 😃
minimal (if any) overhead in terms of latency and throughput 😃 💩
Comparing Push vs Pull
& 39
Supply
Demand
40
Publisher Subscriber
data
demand
• “push” when subscriber is faster
• “pull” when publisher is faster
• switches automatically between both
• batching demand allows batching ops
41
Dynamic
Push–Pull
Reactive Streams
42
Requirements Push Pull Both
support potentially unbounded sequences 😃 😃 😃
sender runs separately from receiver 😃 😃 😃
rate of reception may vary from rate of sending 😃 😃 😃
dropping elements should be a choice and not a necessity 💩 😃 😃
minimal (if any) overhead in terms of latency and throughput 😃 💩 😃
Comparing Push vs Pull vs Both
🌟
Stream splitting
43
demand
data
splitting the data means merging the demand
Stream merging
44
merging the data means splitting the demand
Source Flow Sink
RunnableGraph
46
streams: Linear transformations
val fives = Source.repeat(5)
val timesTwo = Flow[Int].map(_ * 2)
val intToString = Flow[Int].map(_.toString)
val transform = timesTwo via intToString
val sysOut = Sink.foreach(println)
val r = fives via transform.take(10) to sysOut


r.run() // a Materializer needs to be in scope
BidiFlows
48
streams: Selected BidiFlows Examples
val codec: 

BidiFlow[Foo, ByteString, ByteString, Foo, Unit] = …



val crypto:

BidiFlow[ByteString, ByteString, ByteString, ByteString, Unit] = …



val framing: 

BidiFlow[ByteString, ByteString, ByteString, ByteString, Unit] = …



val protocol = codec atop crypto atop framing
DAG
DCG
WAT
Fan-In
Fan-Out
&
Fan-tastic!
52
streams: Cthulhu-Merge-Route Explained
OI
Materialization
55
streams: Materialization
• Akka Streams separates the what from the how & when
• declarative Source/Flow/Sink DSL to create a blueprint
• ActorMaterializer turns this into running Actors
• enables customizable materialization strategies
• optimization
• verification / validation
• distributed deployment
56
streams: MaterializedValues
• At Compositiontime
• MaterializedValues of respective sides are composed
• At Materializationtime
• A value of the final type of the MaterializedValue

of the graph is returned
57
streams: Composition
58
streams: Composition
val runnableGraph = FlowGraph.closed() { implicit builder =>
import FlowGraph.Implicits._
val A: Outlet[Int] = builder.add(Source.single(0))
val B: UniformFanOutShape[Int, Int] = builder.add(Broadcast[Int](2))
val C: UniformFanInShape[Int, Int] = builder.add(Merge[Int](2))
val D: FlowShape[Int, Int] = builder.add(Flow[Int].map(_ + 1))
val E: UniformFanOutShape[Int, Int] = builder.add(Balance[Int](2))
val F: UniformFanInShape[Int, Int] = builder.add(Merge[Int](2))
val G: Inlet[Any] = builder.add(Sink.foreach(println))
C <~ F
A ~> B ~> C ~> F
B ~> D ~> E ~> F
E ~> G
}
59
streams: Composition
Functional Programming
Akka Streams
Akka Typed
Functional Programming
60
streams: Future?
Functional Programming
Akka Streams
Akka Typed
Functional Programming
61
Summary
Akka Streams and Akka Typed promises
both the compositionalstrengths of FP,
paired with the communicationalstrengths
and resilience of the Actor Model.
√
Opportunity: Self-tuning back pressure
63
• Each processing stage can know
• Latency between requesting more and getting more
• Latency for internal processing
• Behavior of downstream demand
• Latency between satisfying and receiving more
• Trends in requested demand (patterns)
• Lock-step
• N-buffered
• N + X-buffered
• “chaotic”
Opportunity: Operation elision
64
• Compile-time, using Scala Macros
• fold ++ take(n where n > 0) == fold
• drop(0) == identity
• <any> ++ identity == <any>
• Run-time, using intra-stage simplification
• map ++ dropUntil(cond) ++ take(N)
• map ++ identity ++ take(N)
• map ++ take(N)
Opportunity: Operation fusion
65
• Compile-time, using Scala Macros
• filter ++ map == collect
• Run-time, using intra-stage simplification
• Rule: <any> ++ identity == <any>

Rule: identity ++ <any> == <any>
• filter ++ dropUntil(cond) ++ map
• filter ++ identity ++ map == collect
Opportunity: Execution optimization
66
• synchronous intra-stage execution N steps then
trampoline and/or give control to other Thread /
Flow
67
public interface Publisher<T> {
public void subscribe(Subscriber<T> s);
}
public void Subscription {
public void request(long n);
public void cancel();
}
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
public interface Processor<T, R>
extends Subscriber<T>, Publisher<R> { }
How does it connect?
68
SubscriberPublisher
subscribe(subscriber)
onSubscribe(subscription)
How does data flow?
69
SubscriberPublisher
subscription.request(1)
onNext(element)
subscription.request(3)
onNext(element)
subscription.request(1)
How does data flow?
70
SubscriberPublisher
onNext(element)
onNext(element)
subscription.request(2)
onNext(element)
onNext(element)
How does it complete?
71
SubscriberPublisher
subscription.request(1)
onNext(element)
onComplete()
onNext(element)
What if it fails?
72
SubscriberPublisher
subscription.request(1)
onNext(element)
subscription.request(5)
onError(exception)
☠
73
Try Akka Streams: (1.0)

https://github.com/typesafehub/activator-akka-stream-scala
References
Reactive Streams for JVM

https://github.com/reactive-streams/reactive-streams-jvm

Functional Programming and Composing Actors

  • 1.
  • 3.
  • 4.
  • 5.
    5 Klang’s Conjecture «If youcannot solve a problem without programming; you cannot solve a problem with programming.»
  • 6.
  • 7.
  • 8.
    Reality • separation inspace & time gives us • communication for coordination • variable delays • partial failures • only partial/local/stale knowledge • systems 8
  • 9.
    9 system «a set ofthings working together as parts of a mechanism or an interconnecting network;
 a complex whole» noun
  • 10.
    Systems • Purpose istypically simple • Complex inner workings • Consist of collaborating components • Components can be systems themselves • Components are as simple as feasible, but not simpler 10
  • 11.
    11 Resilience «Any sufficiently complexsystem is always running in degraded mode» — Richard I. Cook, MD “How complex systems fail” (paraphrased)
  • 12.
    Communication • The productionand consumption of messages • Messaging implies that we need to be able to address recipients • Addresses/Identities are important • They are knowledge that can be shared • Messages can become delayed, lost 
 or misunderstood 12
  • 13.
    Think: Reliability • Arewe ever guaranteed delivery? • at-most-once • at-least-once • exactly-once • It’s not about guarantees,
 it’s about reliability 13
  • 14.
  • 15.
    Burstiness • Most communicationis bursty • some is predictable • some is unpredictable • load shedding can cause burstiness 15
  • 16.
    Flow control /Back pressure 16 • Buffers are only grease between cogs • Does not solve overload problems • Load shedding does not inform sender • Reasons • When shedding will end www.reactive-­‐streams.org
  • 17.
    Resilience • Never assumethat other entities are immortal • Treat expectation violations as failures • Always have a Plan B • Clients are not responsible to fix a faulty provider • Fail fast & predictably 17
  • 18.
    18 Supervision • Responsibility todeal with the failure/corruption of other • Does not place the burden of fixing it on the collaborators «Quis custodiet ipsos custodes?» — Decimus Iunius Iuvenalis
  • 19.
    19 actors • Akka's unitof computation is called an actor • Akka actors are purely reactive components: • Current behavior • Address • Local storage • Mailbox • Scheduled to execute when sent a message • An actor has a parent actor, handling its failures • An actor may have 0..N child actors
  • 20.
    20 « 2500 nodes× millions of actors per GB RAM = a lot» actors • An actor processes a message at a time • Multiple-producers & Single-consumer • The overhead per actor is about ~450bytes • Run millions of actors on commodity hardware • Akka Cluster currently handles ~2500 nodes actors
  • 21.
    21 actors • Great for •Communication • Location transparency • Elasticity • Resilience • Main challenge • Composition
  • 22.
  • 23.
    23 Functional Programming • Greatfor • Composition • Main challenge • Communication • Resilience
  • 24.
    24 typed: On thehorizon • Project Gålbma • distill an Actor to its essence: the Behavior • everything is a message—for real this time • remove the danger to close over Actor environment • behavior composition • completely pure Actor implementation,
 through a process algebra (inspired by JoinCalculus)
  • 25.
    Behavior is King 25 abstractclass Behavior[T] { def management(ctx: ActorContext[T], msg: Signal): Behavior[T] def message(ctx: ActorContext[T], msg: T): Behavior[T] def narrow[U <: T]: Behavior[U] = this.asInstanceOf[Behavior[U]] }
  • 26.
    Behavior example 26 object Server{ sealed trait Command case class Get(id: Int)(val replyTo: ActorRef[Got]) extends Command case class Put(name: String, ref: ActorRef[OtherCommand]) extends Command case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]]) val initial: Behavior[Command] = withMap(Map.empty) private def withMap(map: Map[String, ActorRef[OtherCommand]]) = Total[Command] { case g @ Get(id) => g.replyTo ! Got(id, Map.empty) Same case Put(name, ref) => withMap(map.updated(name, ref)) } }
  • 27.
    Most common devtask? • Receive inputs • Transform data • Produce outputs • Drink coffee 27
  • 28.
    28 #undef STREAMS #defineSTREAMS • ephemeral, time-dependent, sequences of elements • possibly unbounded in length • in essence: transformation & transportation of data «No man ever steps in the same river twice, for it's not the same river and he's not the same man.» — Heraclitus
  • 29.
  • 30.
    i m mu t a b l e REUSABLE c o m p o s a b l e c o o r d i n a t e d
 asynchronous
 transformations
  • 31.
    Getting data across anasynchronous b o u n d a r y
  • 36.
    Getting data across anasynchronous b o u n d a r y
 with non-blocking
 back pressure
  • 37.
  • 38.
    38 Requirements Push Pull supportpotentially unbounded sequences 😃 😃 sender runs separately from receiver 😃 😃 rate of reception may vary from rate of sending 😃 😃 dropping elements should be a choice and not a necessity 💩 😃 minimal (if any) overhead in terms of latency and throughput 😃 💩 Comparing Push vs Pull
  • 39.
  • 40.
  • 41.
    • “push” whensubscriber is faster • “pull” when publisher is faster • switches automatically between both • batching demand allows batching ops 41 Dynamic Push–Pull Reactive Streams
  • 42.
    42 Requirements Push PullBoth support potentially unbounded sequences 😃 😃 😃 sender runs separately from receiver 😃 😃 😃 rate of reception may vary from rate of sending 😃 😃 😃 dropping elements should be a choice and not a necessity 💩 😃 😃 minimal (if any) overhead in terms of latency and throughput 😃 💩 😃 Comparing Push vs Pull vs Both 🌟
  • 43.
    Stream splitting 43 demand data splitting thedata means merging the demand
  • 44.
    Stream merging 44 merging thedata means splitting the demand
  • 45.
  • 46.
    46 streams: Linear transformations valfives = Source.repeat(5) val timesTwo = Flow[Int].map(_ * 2) val intToString = Flow[Int].map(_.toString) val transform = timesTwo via intToString val sysOut = Sink.foreach(println) val r = fives via transform.take(10) to sysOut 
 r.run() // a Materializer needs to be in scope
  • 47.
  • 48.
    48 streams: Selected BidiFlowsExamples val codec: 
 BidiFlow[Foo, ByteString, ByteString, Foo, Unit] = …
 
 val crypto:
 BidiFlow[ByteString, ByteString, ByteString, ByteString, Unit] = …
 
 val framing: 
 BidiFlow[ByteString, ByteString, ByteString, ByteString, Unit] = …
 
 val protocol = codec atop crypto atop framing
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
    55 streams: Materialization • AkkaStreams separates the what from the how & when • declarative Source/Flow/Sink DSL to create a blueprint • ActorMaterializer turns this into running Actors • enables customizable materialization strategies • optimization • verification / validation • distributed deployment
  • 56.
    56 streams: MaterializedValues • AtCompositiontime • MaterializedValues of respective sides are composed • At Materializationtime • A value of the final type of the MaterializedValue
 of the graph is returned
  • 57.
  • 58.
    58 streams: Composition val runnableGraph= FlowGraph.closed() { implicit builder => import FlowGraph.Implicits._ val A: Outlet[Int] = builder.add(Source.single(0)) val B: UniformFanOutShape[Int, Int] = builder.add(Broadcast[Int](2)) val C: UniformFanInShape[Int, Int] = builder.add(Merge[Int](2)) val D: FlowShape[Int, Int] = builder.add(Flow[Int].map(_ + 1)) val E: UniformFanOutShape[Int, Int] = builder.add(Balance[Int](2)) val F: UniformFanInShape[Int, Int] = builder.add(Merge[Int](2)) val G: Inlet[Any] = builder.add(Sink.foreach(println)) C <~ F A ~> B ~> C ~> F B ~> D ~> E ~> F E ~> G }
  • 59.
    59 streams: Composition Functional Programming AkkaStreams Akka Typed Functional Programming
  • 60.
    60 streams: Future? Functional Programming AkkaStreams Akka Typed Functional Programming
  • 61.
    61 Summary Akka Streams andAkka Typed promises both the compositionalstrengths of FP, paired with the communicationalstrengths and resilience of the Actor Model.
  • 62.
  • 63.
    Opportunity: Self-tuning backpressure 63 • Each processing stage can know • Latency between requesting more and getting more • Latency for internal processing • Behavior of downstream demand • Latency between satisfying and receiving more • Trends in requested demand (patterns) • Lock-step • N-buffered • N + X-buffered • “chaotic”
  • 64.
    Opportunity: Operation elision 64 •Compile-time, using Scala Macros • fold ++ take(n where n > 0) == fold • drop(0) == identity • <any> ++ identity == <any> • Run-time, using intra-stage simplification • map ++ dropUntil(cond) ++ take(N) • map ++ identity ++ take(N) • map ++ take(N)
  • 65.
    Opportunity: Operation fusion 65 •Compile-time, using Scala Macros • filter ++ map == collect • Run-time, using intra-stage simplification • Rule: <any> ++ identity == <any>
 Rule: identity ++ <any> == <any> • filter ++ dropUntil(cond) ++ map • filter ++ identity ++ map == collect
  • 66.
    Opportunity: Execution optimization 66 •synchronous intra-stage execution N steps then trampoline and/or give control to other Thread / Flow
  • 67.
    67 public interface Publisher<T>{ public void subscribe(Subscriber<T> s); } public void Subscription { public void request(long n); public void cancel(); } public interface Subscriber<T> { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); } public interface Processor<T, R> extends Subscriber<T>, Publisher<R> { }
  • 68.
    How does itconnect? 68 SubscriberPublisher subscribe(subscriber) onSubscribe(subscription)
  • 69.
    How does dataflow? 69 SubscriberPublisher subscription.request(1) onNext(element) subscription.request(3) onNext(element) subscription.request(1)
  • 70.
    How does dataflow? 70 SubscriberPublisher onNext(element) onNext(element) subscription.request(2) onNext(element) onNext(element)
  • 71.
    How does itcomplete? 71 SubscriberPublisher subscription.request(1) onNext(element) onComplete() onNext(element)
  • 72.
    What if itfails? 72 SubscriberPublisher subscription.request(1) onNext(element) subscription.request(5) onError(exception) ☠
  • 73.
    73 Try Akka Streams:(1.0)
 https://github.com/typesafehub/activator-akka-stream-scala References Reactive Streams for JVM
 https://github.com/reactive-streams/reactive-streams-jvm