73
& Deputy CTO Functional Programming Composing Actors

Functional Programming and Composing Actors

Embed Size (px)

Citation preview

Page 1: Functional Programming and Composing Actors

&√

Deputy CTO

Functional Programming

Composing Actors

Page 2: Functional Programming and Composing Actors
Page 3: Functional Programming and Composing Actors

&Functional Programming

without sacrificing Communication

Resilience√

Deputy CTO

Page 4: Functional Programming and Composing Actors

4

Connectedness

«Software is becoming increasingly interconnected»

Page 5: Functional Programming and Composing Actors

5

Klang’s Conjecture

«If you cannot solve a problem without programming; you cannot solve a problem with programming.»

Page 6: Functional Programming and Composing Actors

Reality Imaginary>

Page 7: Functional Programming and Composing Actors

My office door

7

Stunning views

Page 8: Functional Programming and Composing Actors

Reality• separation in space & time gives us

• communication for coordination

• variable delays

• partial failures

• only partial/local/stale knowledge

• systems

8

Page 9: Functional Programming and Composing Actors

9

system

«a set of things working together as parts of a mechanism or an interconnecting network;

a complex whole»

noun

Page 10: Functional Programming and Composing Actors

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

Page 11: Functional Programming and Composing Actors

11

Resilience

«Any sufficiently complex system is always running in degraded mode»

— Richard I. Cook, MD “How complex systems fail” (paraphrased)

Page 12: Functional Programming and Composing Actors

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

Page 13: Functional Programming and Composing Actors

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

Page 14: Functional Programming and Composing Actors

Two-Phased Commit

14

Page 15: Functional Programming and Composing Actors

Burstiness• Most communication is bursty

• some is predictable

• some is unpredictable

• load shedding can cause burstiness

15

Page 16: Functional Programming and Composing Actors

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

Page 17: Functional Programming and Composing Actors

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

Page 18: Functional Programming and Composing Actors

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

Page 19: Functional Programming and Composing Actors

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

Page 20: Functional Programming and Composing 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

Page 21: Functional Programming and Composing Actors

21

actors

• Great for • Communication • Location transparency • Elasticity

• Resilience • Main challenge • Composition

Page 22: Functional Programming and Composing Actors

Functional Compositiona → b → c

Page 23: Functional Programming and Composing Actors

23

Functional Programming

• Great for • Composition

• Main challenge • Communication • Resilience

Page 24: Functional Programming and Composing Actors

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 Join Calculus)

Page 25: Functional Programming and Composing Actors

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]]}

Page 26: Functional Programming and Composing Actors

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)) }}

Page 27: Functional Programming and Composing Actors

Most common dev task?

• Receive inputs

• Transform data

• Produce outputs

• Drink coffee

27

Page 28: Functional Programming and Composing Actors

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

Page 29: Functional Programming and Composing Actors

streams

Page 30: Functional Programming and Composing Actors

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 asynchronoustransformations

Page 31: Functional Programming and Composing Actors

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

Page 32: Functional Programming and Composing Actors
Page 33: Functional Programming and Composing Actors
Page 34: Functional Programming and Composing Actors
Page 35: Functional Programming and Composing Actors
Page 36: Functional Programming and Composing Actors

Getting data across an asynchronous b o u n d a r y with non-blockingback pressure

Page 37: Functional Programming and Composing Actors

Reactive Streams Initiative

T H E

Page 38: Functional Programming and Composing Actors

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

Page 39: Functional Programming and Composing Actors

&39

Supply

Demand

Page 40: Functional Programming and Composing Actors

40

Publisher Subscriber

data

demand

Page 41: Functional Programming and Composing Actors

• “push” when subscriber is faster

• “pull” when publisher is faster

• switches automatically between both

• batching demand allows batching ops

41

DynamicPush–Pull

Reactive Streams

Page 42: Functional Programming and Composing Actors

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🌟

Page 43: Functional Programming and Composing Actors

Stream splitting

43

demand

data

splitting the data means merging the demand

Page 44: Functional Programming and Composing Actors

Stream merging

44

merging the data means splitting the demand

Page 45: Functional Programming and Composing Actors

Source Flow Sink

RunnableGraph

Page 46: Functional Programming and Composing Actors

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

Page 47: Functional Programming and Composing Actors

BidiFlows

Page 48: Functional Programming and Composing Actors

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

Page 49: Functional Programming and Composing Actors

DAG

DCGWAT

Page 50: Functional Programming and Composing Actors

Fan-In

Fan-Out&

Page 51: Functional Programming and Composing Actors

Fan-tastic!

Page 52: Functional Programming and Composing Actors

52

streams: Cthulhu-Merge-Route Explained

Page 53: Functional Programming and Composing Actors

OI

Page 54: Functional Programming and Composing Actors

Materialization

Page 55: Functional Programming and Composing Actors

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

Page 56: Functional Programming and Composing Actors

56

streams: MaterializedValues

• At Composition time

• MaterializedValues of respective sides are composed

• At Materialization time

• A value of the final type of the MaterializedValueof the graph is returned

Page 57: Functional Programming and Composing Actors

57

streams: Composition

Page 58: Functional Programming and Composing Actors

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 }

Page 59: Functional Programming and Composing Actors

59

streams: Composition

Functional Programming

Akka Streams

Akka Typed

Functional Programming

Page 60: Functional Programming and Composing Actors

60

streams: Future?

Functional Programming

Akka Streams

Akka Typed

Functional Programming

Page 61: Functional Programming and Composing Actors

61

Summary

Akka Streams and Akka Typed promises both the compositional strengths of FP, paired with the communicational strengths and resilience of the Actor Model.

Page 62: Functional Programming and Composing Actors

Page 63: Functional Programming and Composing Actors

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”

Page 64: Functional Programming and Composing Actors

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)

Page 65: Functional Programming and Composing Actors

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

Page 66: Functional Programming and Composing Actors

Opportunity: Execution optimization

66

• synchronous intra-stage execution N steps then trampoline and/or give control to other Thread / Flow

Page 67: Functional Programming and Composing Actors

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> { }

Page 68: Functional Programming and Composing Actors

How does it connect?

68

SubscriberPublisher

subscribe(subscriber)

onSubscribe(subscription)

Page 69: Functional Programming and Composing Actors

How does data flow?

69

SubscriberPublisher

subscription.request(1)

onNext(element)

subscription.request(3)

onNext(element)

subscription.request(1)

Page 70: Functional Programming and Composing Actors

How does data flow?

70

SubscriberPublisher

onNext(element)

onNext(element)

subscription.request(2)

onNext(element)

onNext(element)

Page 71: Functional Programming and Composing Actors

How does it complete?

71

SubscriberPublisher

subscription.request(1)

onNext(element)

onComplete()

onNext(element)

Page 72: Functional Programming and Composing Actors

What if it fails?

72

SubscriberPublisher

subscription.request(1)

onNext(element)

subscription.request(5)

onError(exception)

Page 73: Functional Programming and Composing Actors

73

Try Akka Streams: (1.0)https://github.com/typesafehub/activator-akka-stream-scala

References

Reactive Streams for JVMhttps://github.com/reactive-streams/reactive-streams-jvm