+ All Categories
Home > Technology > The Need for Async @ ScalaWorld

The Need for Async @ ScalaWorld

Date post: 14-Jan-2017
Category:
Upload: konrad-malawski
View: 3,401 times
Download: 4 times
Share this document with a friend
170
Konrad `@ktosopl` Malawski need for async hot pursuit for Scalable apps ScalaWorld 2015
Transcript
Page 1: The Need for Async @ ScalaWorld

Konrad `@ktosopl` Malawski

need for async hot pursuit

for Scalable apps

ScalaWorld 2015

Page 2: The Need for Async @ ScalaWorld

Konrad `ktoso` Malawski

Akka Team, Reactive Streams TCK

(we’re renaming soon!)

Page 3: The Need for Async @ ScalaWorld

Konrad `@ktosopl` Malawski

akka.iotypesafe.comgeecon.org

Java.pl / KrakowScala.plsckrk.com / meetup.com/Paper-Cup @ London

GDGKrakow.pl lambdakrk.pl

(we’re renaming soon!)

Page 4: The Need for Async @ ScalaWorld

Nice to meet you! Who are you guys?

Page 5: The Need for Async @ ScalaWorld

High Performance Software Development

For the majority of the time, high performance software development

is not about compiler hacks and bit twiddling.

It is about fundamental design principles that are key to doing any effective software development.

Martin Thompson

practicalperformanceanalyst.com/2015/02/17/getting-to-know-martin-thompson-...

Page 6: The Need for Async @ ScalaWorld

Agenda

• Why?

• Async and Synch basics / definitions

• Async where it matters: Scheduling

• How NOT to measure Latency

• Concurrent < lock-free < wait-free

• I/O: IO, AIO, NIO, Zero

• Sorting a.k.a. hiding the horrible mutable stuff

• Distributed Systems: Where Async is at Home

• Wrapping up and Q/A

Page 7: The Need for Async @ ScalaWorld

Why?

Page 8: The Need for Async @ ScalaWorld

Why this talk?

“The free lunch is over” Herb Sutter

(A Fundamental Turn Toward Concurrency in Software)

Page 9: The Need for Async @ ScalaWorld

Why this talk?

“The free lunch is over” Herb Sutter

(A Fundamental Turn Toward Concurrency in Software)

How and why Asynchronous Processing

comes into play for Scalability and Performance.

Page 10: The Need for Async @ ScalaWorld

Why this talk?

“The free lunch is over” Herb Sutter

(A Fundamental Turn Toward Concurrency in Software)

How and why Asynchronous Processing

comes into play for Scalability and Performance.

I want you guys makewell informed decisions,

not buzzword driven development.

Page 11: The Need for Async @ ScalaWorld

Sync / Async Basics

Page 12: The Need for Async @ ScalaWorld

Sync / Async

Page 13: The Need for Async @ ScalaWorld

Sync / Async

Page 14: The Need for Async @ ScalaWorld

Sync / Async

Page 15: The Need for Async @ ScalaWorld

Sync / Async

Page 16: The Need for Async @ ScalaWorld

Sync / Async

Page 17: The Need for Async @ ScalaWorld

Sync / Async

Page 18: The Need for Async @ ScalaWorld

Sync / Async

Page 19: The Need for Async @ ScalaWorld

Sync / Async

Page 20: The Need for Async @ ScalaWorld

Sync / Async

Page 21: The Need for Async @ ScalaWorld

Highly parallel systemsEvent loops

Actors

Async where it matters:

Page 22: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 23: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 24: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 25: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 26: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 27: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 28: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 29: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 30: The Need for Async @ ScalaWorld

Async where it matters: Scheduling

Page 31: The Need for Async @ ScalaWorld

Scheduling (notice they grey sync call)

Page 32: The Need for Async @ ScalaWorld

Scheduling (notice they grey sync call)

Page 33: The Need for Async @ ScalaWorld

Scheduling (now with Async db call)

Page 34: The Need for Async @ ScalaWorld

Scheduling (now with Async db call)

Page 35: The Need for Async @ ScalaWorld

Scheduling (now with Async db call)

Page 36: The Need for Async @ ScalaWorld

Scheduling (now with Async db call)

Page 37: The Need for Async @ ScalaWorld

Lesson learned:

Blocking is indistinguishable from being very slow.

Page 38: The Need for Async @ ScalaWorld

Latency

Page 39: The Need for Async @ ScalaWorld

Latency Quiz #1: Which one is Latency?By the queueing theory definitions:

Page 40: The Need for Async @ ScalaWorld

Latency Quiz #1: Which one is Latency?By the queueing theory definitions:

Page 41: The Need for Async @ ScalaWorld

Latency Quiz #1: Which one is Latency?By the queueing theory definitions:

Page 42: The Need for Async @ ScalaWorld

Latency Quiz #1: Which one is Latency?By the queueing theory definitions:

Page 43: The Need for Async @ ScalaWorld

Latency Quiz #1: Which one is Latency?

Page 44: The Need for Async @ ScalaWorld

Latency Quiz #1: Which one is Latency?Sometimes devs use Latency and Response Time as the same thing. That’s OK, as long as both sides know which one they are talking about.

Page 45: The Need for Async @ ScalaWorld

Latency Quiz #2

Gil Tene style, see: “How NOT to Measure Latency”

Is 10s latency acceptable in your app? Is 200ms latency acceptable?

How about most responses within 200ms?So mostly 20ms and some 1 minute latencies is OK?

Do people die when we go above 200ms?

So 90% below 200ms, 99% bellow 1s, 99.99% below 2s?

Page 46: The Need for Async @ ScalaWorld

Latency in the “real world”

Gil Tene style, see: “How NOT to Measure Latency”

“Our response time is 200ms average, stddev is around 60ms”

— a typical quote

Page 47: The Need for Async @ ScalaWorld

Latency in the “real world”

Gil Tene style, see: “How NOT to Measure Latency”

“Our response time is 200ms average, stddev is around 60ms”

— a typical quote

Latency does NOT behave like normal distribution!

“So yeah, our 99,99%’ is…”

Page 48: The Need for Async @ ScalaWorld

http://hdrhistogram.github.io/HdrHistogram/

Hiccups

Page 49: The Need for Async @ ScalaWorld

Gil Tene style, see: “How NOT to Measure Latency”

Hiccups

Page 50: The Need for Async @ ScalaWorld

Gil Tene style, see: “How NOT to Measure Latency”

Hiccups

Page 51: The Need for Async @ ScalaWorld

Gil Tene style, see: “How NOT to Measure Latency”

Hiccups

Page 52: The Need for Async @ ScalaWorld

Gil Tene style, see: “How NOT to Measure Latency”

Hiccups

Page 53: The Need for Async @ ScalaWorld

Gil Tene style, see: “How NOT to Measure Latency”

Hiccups

Page 54: The Need for Async @ ScalaWorld

Lesson learned:

Use precise language when talking about latencies. Measure the right thing!

“Trust no-one, bench everything!” Verify the results!

Ask on groups or forums.

Page 55: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 56: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 57: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 58: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

“concurrent” data structure

Page 59: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-freeWhat can happen in concurrent data structures:

A tries to write; B tries to write; B wins! A tries to write; C tries to write; C wins! A tries to write; D tries to write; D wins! A tries to write; B tries to write; B wins! A tries to write; E tries to write; E wins! A tries to write; F tries to write; F wins! …

Moral? 1) Thread A is a complete loser. 2) Thread A may never make progress.

Page 60: The Need for Async @ ScalaWorld

What can happen in concurrent data structures:

A tries to write; B tries to write; B wins! C tries to write; C wins! D tries to write; D wins! B tries to write; B wins! E tries to write; E wins! F tries to write; F wins! …

Moral? 1) Thread A is a complete loser. 2) Thread A may never make progress.

Concurrent < lock-free < wait-free

Page 61: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-less

Remember: Concurrency is NOT Parallelism.

Rob Pike - Concurrency is NOT Parallelism (video)

def offer(a: A): Boolean // returns on failuredef add(a: A): Unit // throws on failure

def put(a: A): Boolean // blocks until able to enqueue

Page 62: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

concurrent data structure

< lock-free* data structure

* lock-free a.k.a. lockless

Page 63: The Need for Async @ ScalaWorld

What lock-free programming looks like:

Page 64: The Need for Async @ ScalaWorld

An algorithm is lock-free if it satisfies that:When the program threads are run sufficiently long,

at least one of the threads makes progress.

Concurrent < lock-free < wait-free

Page 65: The Need for Async @ ScalaWorld

* Both versions are used: lock-free / lockless

class CASBackedQueue[A] { val _queue = new AtomicReference(Vector[A]())

// may “spin” @tailrec final def put(a: A): Unit = { val queue = _queue.get val appended = queue :+ a

if (!_queue.compareAndSet(queue, appended)) put(a) }}

Concurrent < lock-free < wait-free

Page 66: The Need for Async @ ScalaWorld

class CASBackedQueue[A] { val _queue = new AtomicReference(Vector[A]())

// may “spin” @tailrec final def put(a: A): Unit = { val queue = _queue.get val appended = queue :+ a

if (!_queue.compareAndSet(queue, appended)) put(a) }}

Concurrent < lock-free < wait-free

Page 67: The Need for Async @ ScalaWorld

class CASBackedQueue[A] { val _queue = new AtomicReference(Vector[A]())

// may “spin” @tailrec final def put(a: A): Unit = { val queue = _queue.get val appended = queue :+ a

if (!_queue.compareAndSet(queue, appended)) put(a) }}

Concurrent < lock-free < wait-free

Page 68: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 69: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 70: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 71: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 72: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 73: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Page 74: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

“concurrent” data structure

< lock-free* data structure

< wait-free data structure

* Both versions are used: lock-free / lockless

Page 75: The Need for Async @ ScalaWorld

Concurrent < lock-free < wait-free

Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue AlgorithmsMaged M. Michael Michael L. Scott

An algorithm is wait-free if every operation has a bound on the number of steps the algorithm will take before the

operation completes.

Page 76: The Need for Async @ ScalaWorld

wait-free: j.u.c.ConcurrentLinkedQueue

Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue AlgorithmsMaged M. Michael Michael L. Scott

public boolean offer(E e) { checkNotNull(e); final Node<E> newNode = new Node<E>(e);

for (Node<E> t = tail, p = t;;) { Node<E> q = p.next; if (q == null) { // p is last node if (p.casNext(null, newNode)) { // Successful CAS is the linearization point // for e to become an element of this queue, // and for newNode to become "live". if (p != t) // hop two nodes at a time casTail(t, newNode); // Failure is OK. return true; } // Lost CAS race to another thread; re-read next } else if (p == q) // We have fallen off list. If tail is unchanged, it // will also be off-list, in which case we need to // jump to head, from which all live nodes are always // reachable. Else the new tail is a better bet. p = (t != (t = tail)) ? t : head; else // Check for tail updates after two hops. p = (p != t && t != (t = tail)) ? t : q; }}

This is a modification of the Michael & Scott algorithm,adapted for a garbage-collected environment, with supportfor interior node deletion (to support remove(Object)). For explanation, read the paper.

Page 77: The Need for Async @ ScalaWorld

Act-as-if referentially transparent

Page 78: The Need for Async @ ScalaWorld

Act-as-if referentially transparent

trait Cache[T] { def mut(t: T): Boolean def observe(): List[T] }

Page 79: The Need for Async @ ScalaWorld

Act-as-if referentially transparent class Acc[T] extends Cache[T] { type Observed = Boolean private val _acc = new AtomicReference[(Observed, List[T])]() // could be Array based

@tailrec final def mut(t: T): Boolean = { _acc.get match { case (true, acc) => false // no mutation allowed anymore! case v @ (false, acc) => _acc.compareAndSet(v, (true, t :: acc)) || mut(t) } }

@tailrec final def observe(): List[T] = { _acc.get match { case (true, acc) => acc case v @ (_, acc) => if (!_acc.compareAndSet(v, v.copy(_1 = true))) observe() else acc } } }

I vaguely remember Daniel mentioning this technique some time ago?

Page 80: The Need for Async @ ScalaWorld

Lesson learned:

Different ways to construct concurrent data structures. Pick the right impl for the right job.

Page 81: The Need for Async @ ScalaWorld

I / O

Page 82: The Need for Async @ ScalaWorld

IO / AIO

Page 83: The Need for Async @ ScalaWorld

IO / AIO / NIO

Page 84: The Need for Async @ ScalaWorld

IO / AIO / NIO / Zero

Page 85: The Need for Async @ ScalaWorld

Synchronous I / O

— Havoc Pennington(HAL, GNOME, GConf, D-BUS, now Typesafe)

When I learned J2EE about 2008 with some of my desktop colleagues our reactions included something like:

”wtf is this sync IO crap,

where is the main loop?!” :-)

Page 86: The Need for Async @ ScalaWorld

Interruption!CPU: User Mode / Kernel Mode

Page 87: The Need for Async @ ScalaWorld

Kernels and CPUs

Page 88: The Need for Async @ ScalaWorld

Kernels and CPUs

Page 89: The Need for Async @ ScalaWorld

Kernels and CPUs

Page 90: The Need for Async @ ScalaWorld

Kernels and CPUs

Page 91: The Need for Async @ ScalaWorld

Kernels and CPUs

http://wiki.osdev.org/Context_Switching

Page 92: The Need for Async @ ScalaWorld

Kernels and CPUs

[…] switching from user-level to kernel-level on a (2.8 GHz) P4 is 1348 cycles.

[…] Counting actual time, the P4 takes 481ns […]

http://wiki.osdev.org/Context_Switching

Page 93: The Need for Async @ ScalaWorld

I / O

Page 94: The Need for Async @ ScalaWorld

I / O

Page 95: The Need for Async @ ScalaWorld

I / O

Page 96: The Need for Async @ ScalaWorld

I / O

Page 97: The Need for Async @ ScalaWorld

I / O

Page 98: The Need for Async @ ScalaWorld

I / O

“Don’t worry. It only gets worse!”

Page 99: The Need for Async @ ScalaWorld

I / O“Don’t worry.

It only gets worse!”

Same data in 3 buffers!4 mode switches!

Page 100: The Need for Async @ ScalaWorld

Asynchronous I / O [Linux]

Linux AIO = JVM NIO

Page 101: The Need for Async @ ScalaWorld

Asynchronous I / O [Linux]

NewIO… since 2004!(No-one calls it “new” any more)

Linux AIO = JVM NIO

Page 102: The Need for Async @ ScalaWorld

Asynchronous I / O [Linux]

Less time wasted waiting. Same amount of buffer copies.

Page 103: The Need for Async @ ScalaWorld

ZeroCopy = sendfile [Linux]

“Work smarter. Not harder.”

http://fourhourworkweek.com/

Page 104: The Need for Async @ ScalaWorld

ZeroCopy = sendfile [Linux]

Page 105: The Need for Async @ ScalaWorld

ZeroCopy = sendfile [Linux]

Data never leaves kernel mode!

Page 106: The Need for Async @ ScalaWorld

Lesson learned:

By picking the right tool, you can avoid wasting CPU time.

Asynchronous IO will not beat a synchronous seek throughput-wise but it can allow higher scalability.

Page 107: The Need for Async @ ScalaWorld

Functional outside

Page 108: The Need for Async @ ScalaWorld

Functional outside

Page 109: The Need for Async @ ScalaWorld

Functional outside, Intel inside: Sorting

Jan Pustelnik’s Benchmarks: https://github.com/gosubpl

• Haskell Functional – http://en.literateprograms.org

• Haskell Imperative – http://stackoverflow.com/questions/11481675/using-vectors-for-performance-improvement-in-haskell

• C++ – by-the-book impl, rather simple, plenty examples in books

• Scala – Scala by Example; and ST monadic example from https://github.com/fpinscala/fpinscala/blob/master/answers/src/main/scala/fpinscala/localeffects/LocalEffects.scala (Solutions to Functional programming in Scala by Paul Chiusano and Runar Bjarnason).

Page 110: The Need for Async @ ScalaWorld

Jan Pustelnik’s Benchmarks: https://github.com/gosubpl

Functional outside, Intel inside: Sorting

Page 111: The Need for Async @ ScalaWorld

Jan Pustelnik’s Benchmarks: https://github.com/gosubpl

Functional outside, Intel inside: Sorting

Page 112: The Need for Async @ ScalaWorld

Jan Pustelnik’s Benchmarks: https://github.com/gosubpl

Functional outside, Intel inside: Sorting

Page 113: The Need for Async @ ScalaWorld

Jan Pustelnik’s Benchmarks: https://github.com/gosubpl

Functional outside, Intel inside: Sorting

Page 114: The Need for Async @ ScalaWorld

Scala 2.10.5 – Vector#sorted

def sorted[B >: A](implicit ord: Ordering[B]): Repr = { val len = this.length val arr = new ArraySeq[A](len) var i = 0 for (x <- this.seq) { arr(i) = x i += 1 } java.util.Arrays.sort(arr.array, ord.asInstanceOf[Ordering[Object]]) val b = newBuilder b.sizeHint(len) for (x <- arr) b += x b.result }

Functional outside, Intel inside: Sorting

Page 115: The Need for Async @ ScalaWorld

MicroBenchmarking done right

http://openjdk.java.net/projects/code-tools/jmh/github.com/ktoso/sbt-jmh

Where are we spending time?What and how much are we allocating?

…?

Page 116: The Need for Async @ ScalaWorld

MicroBenchmarking DON’T DO THIS:

https://github.com/travisbrown/circe/issues/59

Page 117: The Need for Async @ ScalaWorld

MicroBenchmarking DON’T DO THIS:

https://github.com/travisbrown/circe/issues/59

Page 118: The Need for Async @ ScalaWorld

MicroBenchmarking done right

http://openjdk.java.net/projects/code-tools/jmh/github.com/ktoso/sbt-jmh

OpenJDK JMH

Page 119: The Need for Async @ ScalaWorld

JMH – perf_events integration

http://openjdk.java.net/projects/code-tools/jmh/github.com/ktoso/sbt-jmh

Perf stats: --------------------------------------------------

4172.776137 task-clock (msec) # 0.411 CPUs utilized 612 context-switches # 0.147 K/sec 31 cpu-migrations # 0.007 K/sec 195 page-faults # 0.047 K/sec 16,599,643,026 cycles # 3.978 GHz [30.80%] <not supported> stalled-cycles-frontend <not supported> stalled-cycles-backend 17,815,084,879 instructions # 1.07 insns per cycle [38.49%] 3,813,373,583 branches # 913.870 M/sec [38.56%] 1,212,788 branch-misses # 0.03% of all branches [38.91%] 7,582,256,427 L1-dcache-loads # 1817.077 M/sec [39.07%] 312,913 L1-dcache-load-misses # 0.00% of all L1-dcache hits [38.66%] 35,688 LLC-loads # 0.009 M/sec [32.58%] <not supported> LLC-load-misses:HG <not supported> L1-icache-loads:HG 161,436 L1-icache-load-misses:HG # 0.00% of all L1-icache hits [32.81%] 7,200,981,198 dTLB-loads:HG # 1725.705 M/sec [32.68%] 3,360 dTLB-load-misses:HG # 0.00% of all dTLB cache hits [32.65%] 193,874 iTLB-loads:HG # 0.046 M/sec [32.56%] 4,193 iTLB-load-misses:HG # 2.16% of all iTLB cache hits [32.44%] <not supported> L1-dcache-prefetches:HG 0 L1-dcache-prefetch-misses:HG # 0.000 K/sec [32.33%]

10.159432892 seconds time elapsed

Page 120: The Need for Async @ ScalaWorld

JMH – perfasm integration

Nitsan Wakart’s blog: http://psy-lob-saw.blogspot.co.uk/2015/07/jmh-perfasm.html

Page 121: The Need for Async @ ScalaWorld

Other tools: Flame Graphs

https://github.com/brendangregg/FlameGraphhttps://github.com/jrudolph/perf-map-agent

Page 122: The Need for Async @ ScalaWorld

Immutable DSL / AST outside

Page 123: The Need for Async @ ScalaWorld

Immutable DSL / AST outside streams engine inside

Page 124: The Need for Async @ ScalaWorld

Immutable DSL + Akka engineWe happen to have:

a pretty performant engine…+

constrained domain =

Page 125: The Need for Async @ ScalaWorld

Immutable DSL + Akka engineWe happen to have:

a pretty performant engine…+

constrained domain =

Page 126: The Need for Async @ ScalaWorld

Immutable DSL + Akka engine

implicit val mat = ActorMaterializer()

val fives = Source.repeat(5)

val timesTwo = Flow[Int].map(_ * 2)val intToString = Flow[Int].map(_.toString)val transform = timesTwo via intToStringval sysOut = Sink.foreach(println)

val r = fives via transform.take(10) to sysOutr.run() // uses implicit Materializer

Page 127: The Need for Async @ ScalaWorld

implicit val mat = ActorMaterializer()

val fives = Source.repeat(5)

val timesTwo = Flow[Int].map(_ * 2)val intToString = Flow[Int].map(_.toString)val transform = timesTwo via intToStringval sysOut = Sink.foreach(println)

val r = fives via transform.take(10) to sysOutr.run() // uses implicit Materializer

Immutable DSL + Akka engine

Page 128: The Need for Async @ ScalaWorld

implicit val mat = ActorMaterializer()

val fives = Source.repeat(5)

val timesTwo = Flow[Int].map(_ * 2)val intToString = Flow[Int].map(_.toString)val transform = timesTwo via intToStringval sysOut = Sink.foreach(println)

val r = fives via transform.take(10) to sysOutr.run() // uses implicit Materializer

Immutable DSL + Akka engine

Page 129: The Need for Async @ ScalaWorld

Decoupled “what?” from “how?”

What?

val g =

val one: Source[Int, Unit] = Source.single(1) val two: Source[Int, Promise[Unit]] = Source.lazyEmpty val three: Source[Int, Unit] = Source.single(3)

Page 130: The Need for Async @ ScalaWorld

Decoupled “what?” from “how?”

What?

val g =

val one: Source[Int, Unit] = Source.single(1) val two: Source[Int, Promise[Unit]] = Source.lazyEmpty val three: Source[Int, Unit] = Source.single(3)

val step1: Source[Int, Promise[Unit]] = Source(one, two, three)(combineMat = (m1, m2, m3) => m2) { implicit b => (on, tw, th) =>

val m = b.add(Merge[Int](3)) on ~> m.in(0) tw ~> m.in(1) th ~> m.in(2)

m.out }

Page 131: The Need for Async @ ScalaWorld

Decoupled “what?” from “how?”

What?

val g =

val one: Source[Int, Unit] = Source.single(1) val two: Source[Int, Promise[Unit]] = Source.lazyEmpty val three: Source[Int, Unit] = Source.single(3)

val step1: Source[Int, Promise[Unit]] = Source(one, two, three)(combineMat = (m1, m2, m3) => m2) { implicit b => (on, tw, th) =>

val m = b.add(Merge[Int](3)) on ~> m.in(0) tw ~> m.in(1) th ~> m.in(2)

m.out }

Page 132: The Need for Async @ ScalaWorld

Decoupled “what?” from “how?”

What?

val g =

val step2 = Flow() { implicit b => val broadcast = b.add(Broadcast[Int](2, eagerCancel = true)) val merge = b.add(Merge[Int](2))

broadcast.out(0) ~> Flow[Int].map(_ + 2) ~> merge.in(0) broadcast.out(1) ~> Flow[Int].map(_ - 2) ~> merge.in(1)

(broadcast.in, merge.out) }

Page 133: The Need for Async @ ScalaWorld

Decoupled “what?” from “how?”

What?

val g =

How?

g.run()(materializer)

Page 134: The Need for Async @ ScalaWorld

Decoupled “what?” from “how?”

What?

val g =

How?

g.run()(materializer)

Lifted representation => inspection + optimisation

Page 135: The Need for Async @ ScalaWorld

Lesson learned:

Being able to drop down to the “mutable-stuff “ is a huge benefit of Scala,

and is very useful in very specific places!

APIs can stay pure and immutable!

Page 136: The Need for Async @ ScalaWorld

Distributed Systems

Page 137: The Need for Async @ ScalaWorld

Distributed Systems“… in which the failure of a computer you didn't even know existed canrender your own computer unusable.”

— Leslie Lamport

http://research.microsoft.com/en-us/um/people/lamport/pubs/distributed-system.txt

Page 138: The Need for Async @ ScalaWorld

Distributed SystemsThe bigger the system, the more “random” latency / failure noise.

Embrace instead of hiding it.

Page 139: The Need for Async @ ScalaWorld

Distributed SystemsBackup Requests

Page 140: The Need for Async @ ScalaWorld

Backup requests

A technique for fighting “long tail latencies”.By issuing duplicated work, when SLA seems in danger.

Page 141: The Need for Async @ ScalaWorld

Backup requests

Page 142: The Need for Async @ ScalaWorld

Backup requests

Page 143: The Need for Async @ ScalaWorld

Backup requests - send

Page 144: The Need for Async @ ScalaWorld

Backup requests - send

Page 145: The Need for Async @ ScalaWorld

Backup requests - send

Page 146: The Need for Async @ ScalaWorld

Backup requests

Avg Std dev 95%ile 99%ile 99.9%ile

No backups 33 ms 1524 ms 24 ms 52 ms 994 ms

After 10ms 14 ms 4 ms 20 ms 23 ms 50 ms

After 50ms 16 ms 12 ms 57 ms 63 ms 68 ms

Jeff Dean - Achieving Rapid Response Times in Large Online Services Peter Bailis - Doing Redundant Work to Speed Up Distributed Queries

Akka - Krzysztof Janosz @ Akkathon, Kraków - TailChoppingRouter (docs, pr)

Page 147: The Need for Async @ ScalaWorld

Lesson learned:

Backup requests allow trade-off increased load for decreased latency.

Page 148: The Need for Async @ ScalaWorld

Distributed SystemsCombined Requests

& Back-pressure

Page 149: The Need for Async @ ScalaWorld

Combined requests & back-pressure

Page 150: The Need for Async @ ScalaWorld

Combined requests & back-pressure

No no no…! Not THAT Back-pressure!

Page 151: The Need for Async @ ScalaWorld

Combined requests & back-pressure

THAT kind of back-pressure:

Page 152: The Need for Async @ ScalaWorld

Combined requests & back-pressure

THAT kind of back-pressure:

www.reactive-streams.org

Page 153: The Need for Async @ ScalaWorld

Combined requests & back-pressure

THAT kind of back-pressure:

www.reactive-streams.org

Page 154: The Need for Async @ ScalaWorld

Combined requests & back-pressure

THAT kind of back-pressure:

www.reactive-streams.org

Page 155: The Need for Async @ ScalaWorld

Combined requests

A technique for avoiding duplicated work.By aggregating requests, possibly increasing latency.

“Wat? Why would I increase latency!?”

Page 156: The Need for Async @ ScalaWorld

Combined requests

Page 157: The Need for Async @ ScalaWorld

Combined requests

Page 158: The Need for Async @ ScalaWorld

Combined requests

Page 159: The Need for Async @ ScalaWorld

Combined requests

Page 160: The Need for Async @ ScalaWorld

Lesson learned:

Back-pressure saves systems from overload.

Combined requests trade higher latency, for less work for the downstream.

Page 161: The Need for Async @ ScalaWorld

Wrapping up

Page 162: The Need for Async @ ScalaWorld

Wrapping up

You don’t need to be a great mechanic to be a great racing driver,

but you must understand how your bolid works!

~ Martin Thompson (in context of Mechanical Sympathy)

Page 163: The Need for Async @ ScalaWorld

Wrapping up

• Someone has to bite the bullet though!

• We’re all running on real hardware.

• Libraries do it so you don’t have to - pick the right one!

Be aware that:

Page 164: The Need for Async @ ScalaWorld

Wrapping up

• Keep your apps pure

• Be aware of internals

• Async all the things!

• Messaging all the way!

• Someone has to bite the bullet though!

• We’re all running on real hardware.

• Libraries do it so you don’t have to - pick the right one!

Be aware that:

Page 165: The Need for Async @ ScalaWorld

Links• akka.io • reactive-streams.org• akka-user

• Gil Tene - How NOT to measure latency, 2013• Jeff Dean @ Velocity 2014• Alan Bateman, Jeanfrancois Arcand (Sun) Async IO Tips @ JavaOne• http://linux.die.net/man/2/select• http://linux.die.net/man/2/poll• http://linux.die.net/man/4/epoll• giltene/jHiccup• Linux Journal: ZeroCopy I, Dragan Stancevis 2013

• Last slide car picture: http://actu-moteurs.com/sprint/gt-tour/jean-philippe-belloc-un-beau-challenge-avec-le-akka-asp-team/2000

Page 166: The Need for Async @ ScalaWorld

Links• http://wiki.osdev.org/Context_Switching• CppCon: Herb Sutter "Lock-Free Programming (or, Juggling Razor Blades)" • http://www.infoq.com/presentations/reactive-services-scale• Gil Tene’s HdrHistogram.org

• http://hdrhistogram.github.io/HdrHistogram/plotFiles.html• Rob Pike - Concurrency is NOT Parallelism (video)• Brendan Gregg - Systems Performance: Enterprise and the Cloud (book)• http://psy-lob-saw.blogspot.com/2015/02/hdrhistogram-better-latency-capture.html• Jeff Dean, Luiz Andre Barroso - The Tail at Scale (whitepaper, ACM)• http://highscalability.com/blog/2012/3/12/google-taming-the-long-latency-tail-when-

more-machines-equal.html• http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-

architects/• Marcus Lagergren - Oracle JRockit: The Definitive Guide (book)• http://mechanical-sympathy.blogspot.com/2013/08/lock-based-vs-lock-free-

concurrent.html• Handling of Asynchronous Events - http://www.win.tue.nl/~aeb/linux/lk/lk-12.html• http://www.kegel.com/c10k.html

Page 167: The Need for Async @ ScalaWorld

Links• www.reactivemanifesto.org/• Seriously the only right way to micro benchmark on the JVM:

• JMH openjdk.java.net/projects/code-tools/jmh/• JMH for Scala: https://github.com/ktoso/sbt-jmh

• http://www.ibm.com/developerworks/library/l-async/• http://lse.sourceforge.net/io/aio.html• https://code.google.com/p/kernel/wiki/AIOUserGuide• ShmooCon: C10M - Defending the Internet At Scale (Robert Graham)

• http://blog.erratasec.com/2013/02/scalability-its-question-that-drives-us.html#.VO6E11PF8SM

• User-level threads....... with threads. - Paul Turner @ Linux Plumbers Conf 2013• https://www.facebook.com/themainstreetpiggyboys/photos/a.

1390784047896753.1073741829.1390594984582326/1423592294615928/?type=1&theater for the Rollin’ Cuy on last slide

Page 168: The Need for Async @ ScalaWorld

Special thanks to:

• Aleksey Shipilëv• Andrzej Grzesik• Gil Tene• Kirk Pepperdine• Łukasz Dubiel• Marcus Lagergren• Martin Thompson• Mateusz Dymczyk• Nitsan Wakart

Thanks guys, you’re awesome.

alphabetically, mostly

• Peter Lawrey• Richard Warburton• Roland Kuhn• Runar Bjarnason• Sergey Kuksenko• Steve Poole• Viktor Klang a.k.a. √• Antoine de Saint Exupéry;-)• and the entire Akka Team• the Mechanical Sympathy Mailing List

Page 169: The Need for Async @ ScalaWorld

Thanks & Q/A!

ktoso @ typesafe.com twitter: ktosopl

github: ktosoteam blog: letitcrash.com

home: akka.io

Page 170: The Need for Async @ ScalaWorld

©Typesafe 2015 – All Rights Reserved


Recommended