Akka Streams and HTTP

58
Akka Streams & HTTP Dr. Roland Kuhn @rolandkuhn — Akka Tech Lead

Transcript of Akka Streams and HTTP

Page 1: Akka Streams and HTTP

Akka Streams & HTTPDr. Roland Kuhn

@rolandkuhn — Akka Tech Lead

Page 2: Akka Streams and HTTP

Streams Occur Naturally

• traditionally: • file input/output

• network connections

• more modern: • processing big data with finite memory

• real-time data processing (CEP)

• serving numerous clients simultaneously with bounded resources (IoT, streaming HTTP APIs)

2

Page 3: Akka Streams and HTTP

3

What is a Stream?

• ephemeral, time-dependent sequence of elements

• possibly unbounded in length

• therefore focusing on transformations

«You cannot step twice into the same stream. For as you are stepping in, other waters are ever

flowing on to you.» — Heraclitus

Page 4: Akka Streams and HTTP

Reactive Traits

4

Page 5: Akka Streams and HTTP

Reactive means Message Flow

5

Page 6: Akka Streams and HTTP

Reactive means Message Flow

6

37% discount with code

kuhnco

Page 7: Akka Streams and HTTP

Distributed vs. Static Typing

• in general a very tough problem • independent entities evolving concurrently

• promising progress on Project Gålbma

• in many specific cases no type evolution necessary • letting uniform messages flow in safe conduits

• making streams even more interesting

7

Page 8: Akka Streams and HTTP

Possible Solutions

• the Traditional way: blocking calls

8

Page 9: Akka Streams and HTTP

Possible Solutions

• the Push way: buffering and/or dropping(optimized for fast consumer)

9

Page 10: Akka Streams and HTTP

Possible Solutions

• the Pull way: poor performance(optimized for fast producer)

10

Page 11: Akka Streams and HTTP

Possible Solutions

• the Reactive way:non-blocking & non-dropping & bounded

11

Page 12: Akka Streams and HTTP

Reactive Streams

Page 13: Akka Streams and HTTP

Origin and motivation

• all participants face the same basic problem

• all are building tools for their community

• a common solution benefits everybody

• interoperability to make best use of efforts

• propose to include in future JDK

13

Page 14: Akka Streams and HTTP

Goals

• minimal interfaces—essentials only

• rigorous specification of semantics

• TCK for verification of implementation

• complete freedom for many idiomatic APIs

• specification should be efficiently implementable

14

Page 15: Akka Streams and HTTP

Reactive Streams

• asynchronous & non-blocking • flow of data

• flow of demand

• minimal coordination and contention

• message passing allows for distribution across • applications, nodes, CPUs, threads, actors

15

Page 16: Akka Streams and HTTP

A Data Market using Supply & Demand

• data elements flow downstream

• demand flows upstream

• data elements flow only when there is demand

• data in flight is bounded by signaled demand

• recipient is in control of maximal incoming data rate

16

Publisher Subscriber

data

demand

Page 17: Akka Streams and HTTP

Reactive Push–Pull

• “push”—when consumer is faster

• “pull”—when producer is faster

• switches automatically between these

• batching demand allows batching data

17

Publisher Subscriber

data

demand

Page 18: Akka Streams and HTTP

Explicit Demand: One-to-many

18

demand

data

Splitting the data means merging the demand

Page 19: Akka Streams and HTTP

Explicit Demand: Many-to-one

19

Merging the data means splitting the demand

Page 20: Akka Streams and HTTP

Back-Pressure is Contagious

• C is slow

• B must slow down

• A must slow down

20

CA B

Page 21: Akka Streams and HTTP

• TCP for example has it built-in

Back-Pressure can be Propagated

21

CA B

netw

ork

host

s

Page 22: Akka Streams and HTTP

The Meat

22

trait Publisher[T] { def subscribe(sub: Subscriber[T]): Unit } trait Subscription { def request(n: Long): Unit def cancel(): Unit } trait Subscriber[T] { def onSubscribe(s: Subscription): Unit def onNext(e: T): Unit def onError(t: Throwable): Unit def onComplete(): Unit }

Not user-level API

Intended as SPI for interop

Page 23: Akka Streams and HTTP

Akka Streams

Page 24: Akka Streams and HTTP

Declaring a Stream Topology

24

Page 25: Akka Streams and HTTP

Declaring a Stream Topology

25

Page 26: Akka Streams and HTTP

Declaring a Stream Topology

26

Page 27: Akka Streams and HTTP

Declaring a Stream Topology

27

Page 28: Akka Streams and HTTP

Declaring a Stream Topology

28

Page 29: Akka Streams and HTTP

Declaring a Stream Topology

29

Page 30: Akka Streams and HTTP

Declaring a Stream Topology

30

Page 31: Akka Streams and HTTP

API Design

• goals: • no magic

• supreme compositionality

• exhaustive model of bounded stream processing

• consequences: • immutable and reusable stream blueprints

• explicit materialization step

31

http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0-M2/stream-design.html

Page 32: Akka Streams and HTTP

Declaring and Running a Stream

32

val upper = Source(Iterator from 0).take(10)val lower = Source(1.second, 1.second, () => Tick) val source = Source[(Int, Tick)]() { implicit b => val zip = Zip[Int, Tick] val out = UndefinedSink[(Int, Tick)] upper ~> zip.left ~> out lower ~> zip.right out}val flow = Flow[(Int, Tick)].map{ case (x, _) => s"tick $x" }val sink = Sink.foreach(println) val future = source.connect(flow).runWith(sink)

Page 33: Akka Streams and HTTP

Declaring and Running a Stream

33

val upper = Source(Iterator from 0).take(10)val lower = Source(1.second, 1.second, () => Tick) val source = Source[(Int, Tick)]() { implicit b => val zip = Zip[Int, Tick] val out = UndefinedSink[(Int, Tick)] upper ~> zip.left ~> out lower ~> zip.right out}val flow = Flow[(Int, Tick)].map{ case (x, _) => s"tick $x" }val sink = Sink.foreach(println) val future = source.connect(flow).runWith(sink)

Page 34: Akka Streams and HTTP

Declaring and Running a Stream

34

val upper = Source(Iterator from 0).take(10)val lower = Source(1.second, 1.second, () => Tick) val source = Source[(Int, Tick)]() { implicit b => val zip = Zip[Int, Tick] val out = UndefinedSink[(Int, Tick)] upper ~> zip.left ~> out lower ~> zip.right out}val flow = Flow[(Int, Tick)].map{ case (x, _) => s"tick $x" }val sink = Sink.foreach(println) val future = source.connect(flow).runWith(sink)

Page 35: Akka Streams and HTTP

Materialization

• Akka Streams separate the what from the how • declarative Source/Flow/Sink DSL to create blueprint

• FlowMaterializer turns this into running Actors

• this allows alternative materialization strategies • optimization

• verification / validation

• cluster deployment

• only Akka Actors for now, but more to come!

35

Page 36: Akka Streams and HTTP

Stream Sources

• org.reactivestreams.Publisher[T] • org.reactivestreams.Subscriber[T] • Iterator[T] / Iterable[T] • Code block (function that produces Option[T])

• scala.concurrent.Future[T] • TickSource

• ActorPublisher

• singleton / empty / failed

• … plus write your own (fully extensible)

36

Page 37: Akka Streams and HTTP

Stream Sinks

• org.reactivestreams.Publisher[T] • org.reactivestreams.Subscriber[T] • ActorSubscriber

• scala.concurrent.Future[T] • blackhole / foreach / fold / onComplete

• … or create your own

37

Page 38: Akka Streams and HTTP

Linear Stream Transformations

• Deterministic (like for collections) • map, filter, collect, grouped, drop, take, groupBy, …

• Time-Based • takeWithin, dropWithin, groupedWithin, …

• Rate-Detached • expand, conflate, buffer, …

• asynchronous • mapAsync, mapAsyncUnordered, flatten, …

38

Page 39: Akka Streams and HTTP

Nonlinear Stream Transformations

• Fan-In • merge, concat, zip, …

• Fan-Out • broadcast, route, balance, unzip, …

39

Page 40: Akka Streams and HTTP

Akka HTTP

Page 41: Akka Streams and HTTP

Why do we add an HTTP module?

• Akka is about building distributed applications

• distribution implies integration • between internal (sub)systems➜ akka-cluster based on akka-remote

• with external systems➜ akka-http (lingua franca of the internet)

41

Page 42: Akka Streams and HTTP

Akka HTTP—The Origins: Spray.IO

• Fully embeddable HTTP stack based on Actors

• focused on HTTP integration (toolkit)

• server- and client-side

• seamlessly integrated with Akka

42

Page 43: Akka Streams and HTTP

Spray.IO Features

• immutable, case class-based HTTP model

• fast, lightweight HTTP client and server

• powerful DSL for server-side API definition

• fully async & non-blocking, actor-friendly,modular, testable

• based entirely on Scala & Akka Actors

43

Page 44: Akka Streams and HTTP

Spray.IO Weaknesses

• handling of chunked requests is clunky, incomplete

• dealing with large message entities can be difficult

• some unintuitive corner-cases in routing DSL

• deep implicit argument chains in some cases hard to debug

• missing features, foremost websocket support

44

Page 45: Akka Streams and HTTP

Proxying Large Responses

45

Page 46: Akka Streams and HTTP

Akka HTTP is Spray 2.0

• addressing the weaknesses, polishing the features

• Java API

• simplified module structure

• core improvement: fully stream-based

46

Page 47: Akka Streams and HTTP

HTTP Stream Topology

47

Page 48: Akka Streams and HTTP

The Application Stack

48

O/S-level network stack

Java NIO (JDK)

Akka IO

Akka HTTP Core

Akka HTTP

user- level

Page 49: Akka Streams and HTTP

Akka IO

• bridges Java NIO with Akka Actors or streams

• supports TCP, UDP and SSL

49

Page 50: Akka Streams and HTTP

Akka HTTP Core

• implements HTTP/1.1 according to the RFCs

• based upon the TCP facilities of Akka IO

• exposed as freely reusable stream transformations

• low-level and extensible implementation ofHTTP model and spec

50

Page 51: Akka Streams and HTTP

A Quick View of the HTTP Model

51

case class HttpRequest( method: HttpMethod = HttpMethods.GET, uri: Uri = Uri./, headers: immutable.Seq[HttpHeader] = Nil, entity: RequestEntity = HttpEntity.Empty, protocol: HttpProtocol = HttpProtocols.`HTTP/1.1` ) extends HttpMessage

case class HttpResponse( status: StatusCode = StatusCodes.OK, headers: immutable.Seq[HttpHeader] = Nil, entity: ResponseEntity = HttpEntity.Empty, protocol: HttpProtocol = HttpProtocols.`HTTP/1.1` ) extends HttpMessage

Page 52: Akka Streams and HTTP

Akka HTTP

• builds upon Akka HTTP Core

• adds (un)marshaling for HttpEntities

• adds (de)compression (gzip / deflate)

• high-level server-side routing DSL • type-safe and flexible

• highly compositional building blocks (Directives)

• includes common behaviors pre-canned

52

Page 53: Akka Streams and HTTP

Stream Pipelines

53

TCP SSL HTTP App

Requests

Responsesoptional (not yet)

Page 54: Akka Streams and HTTP

A Simple Server Example

54

import Directives._

val binding = Http().bind("localhost", 8080) binding startHandlingWith { path("order" / HexIntNumber) { id => get { complete(s"Received GET for order $id") } ~ put { complete((actor ? Put(id)).mapTo[String]) } } }

Page 55: Akka Streams and HTTP

Summary

Page 56: Akka Streams and HTTP

When can we have it?

• currently pre-release versions: • reactive-streams 1.0.0-RC1

• Akka Streams & HTTP 1.0-M2

• still missing: • Akka HTTP client features

• SSL integration

• websockets

• Akka Streams & HTTP 1.0 expected end of Feb’15

56

Page 57: Akka Streams and HTTP

Resources

• https://github.com/akka/akka/tree/release-2.3-dev

• http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0-M2/

• akka-user mailing list

57

Page 58: Akka Streams and HTTP

©Typesafe 2014 – All Rights Reserved