a dive into akka streams: from the basics to a real-world scenario

42
A dive into Akka Streams From the basics to a real-world scenario Gioia Ballin, Simone Fabiano - SW developers

Upload: gioia-ballin

Post on 07-Jan-2017

8.966 views

Category:

Software


2 download

TRANSCRIPT

Page 1: A dive into akka streams: from the basics to a real-world scenario

A dive into Akka StreamsFrom the basics to a real-world scenario

Gioia Ballin, Simone Fabiano - SW developers

Page 2: A dive into akka streams: from the basics to a real-world scenario

Who are these guys?Gioia Ballin

Twitter / @GioiaBallinSimone Fabiano

Twitter / @mone_tpatpc

R&D Data Analysis Microservices Infrastructure WebBlog

Page 3: A dive into akka streams: from the basics to a real-world scenario

AgendaThe Problem

Akka Streams Basics

The Collector Service

Recap and Learnings

Page 4: A dive into akka streams: from the basics to a real-world scenario

Data processing pipelineCOLLECTOR SVC AMAZON KINESIS

WI-F

I/3G

SEN

SOR

S

Page 5: A dive into akka streams: from the basics to a real-world scenario

The Collector Service: two months ago...

AMAZON KINESIS

INBOX

ACTORTCP

Kinesis Client

INBOX

ACTOR Kinesis Client

INBOX

ACTOR Kinesis Client

TCP

TCP

chun

ks

chunks

chunks

events

events

events

put

put

put

Page 6: A dive into akka streams: from the basics to a real-world scenario
Page 7: A dive into akka streams: from the basics to a real-world scenario

Data may be lostCOLLECTOR SVC AMAZON KINESIS

WI-F

I/3G

SEN

SOR

S

CONNECTION ISSUES

MESSAGE OVERLOAD

Page 8: A dive into akka streams: from the basics to a real-world scenario

Not REALLY reactive: why?Lack of...

RECOVERY MECHANISMS

BACKPRESSURE

Page 9: A dive into akka streams: from the basics to a real-world scenario

Recovery mechanisms

Upload failure? Retry

Kinesis unavailable? Buffer

Page 10: A dive into akka streams: from the basics to a real-world scenario

Ingestion speed under control

Take advantage of sensors buffer

Sensors switch from busier to less busy services

Page 11: A dive into akka streams: from the basics to a real-world scenario

Welcome Akka Streams!

Backpressure on the network

+

Easy fit for stream paradigm

Typed flow & Increased Readability

Page 12: A dive into akka streams: from the basics to a real-world scenario

Akka Streams Basics - 3 2 1 Go!

Page 13: A dive into akka streams: from the basics to a real-world scenario

SOURCE FLOW SINK

Page 14: A dive into akka streams: from the basics to a real-world scenario

val source = Source(1 to 42) val flow = Flow[Int].map(_ + 1) val sink = Sink.foreach(println)

val graph = source.via(flow).to(sink)

graph.run()

Page 15: A dive into akka streams: from the basics to a real-world scenario

Flows are collections (almost)

OK map, filter, fold, …

No flatMap! (there’s mapConcat though)

Extras mapAsync, mapAsyncUnordered, buffer..

Page 16: A dive into akka streams: from the basics to a real-world scenario

How backpressure worksSource Flow Sink

pull

pull

push

push

Page 17: A dive into akka streams: from the basics to a real-world scenario

Collector with Akka Streams

Page 18: A dive into akka streams: from the basics to a real-world scenario

path("data") { post { extractRequest { request =>

val source = request.entity.dataBytes val flow = processing() val sink = Sink.ignore

source.via(flow).runWith(sink)

… } }

Page 19: A dive into akka streams: from the basics to a real-world scenario

Flow[ByteString] .via(chunkBuffer)

Page 20: A dive into akka streams: from the basics to a real-world scenario

Transformation tools: Framing.delimiter

val chunkBuffer = Framing.delimiter( ByteString("\n"), maxPresenceEventBytes, false

) .map(_.dropRight(1)) .map(_.utf8String)

Page 21: A dive into akka streams: from the basics to a real-world scenario

Flow[ByteString]

.via(chunkBuffer)

.via(presenceEventFactory.asStream)

Page 22: A dive into akka streams: from the basics to a real-world scenario

Flow[ByteString]

.via(chunkBuffer)

.via(presenceEventFactory.asStream)

.via(persistentBuffer)

Page 23: A dive into akka streams: from the basics to a real-world scenario

class PersistentBuffer[A] (...) extends GraphStage[FlowShape[A, A]] {

val in = Inlet[A]("PersistentBuffer.in")

val out = Outlet[A]("PersistentBuffer.out")

override val shape = FlowShape.of(in,out)

When the available stages are not enough, write your own

Page 24: A dive into akka streams: from the basics to a real-world scenario

Custom stages: State

override def createLogic( attr: Attributes ): GraphStageLogic =

new GraphStageLogic(shape) {

var state: StageState[A] = initialState[A]

Page 25: A dive into akka streams: from the basics to a real-world scenario

val cb = getAsyncCallback[Try[A]] { case Success(elements:A) => state = state.copy(...) ... }

queue.getCurrentQueue .onComplete(cb.invoke)

Page 26: A dive into akka streams: from the basics to a real-world scenario

Custom Stages: ports

setHandler(in, new InHandler { override def onPush() = { val element = grab(in) pull(in)

... } ... }) setHandler(out, new OutHandler { override def onPull(): Unit = { push(out, something) } ... })

Page 27: A dive into akka streams: from the basics to a real-world scenario

Custom Stages: Start and stop

override def postStop(): Unit = { ... }

override def preStart(): Unit = { ... }

Page 28: A dive into akka streams: from the basics to a real-world scenario

Flow[ByteString]

.via(chunkBuffer)

.via(presenceEventFactory.asStream)

.via(persistentBuffer)

.via(kinesisPublisher)

Page 29: A dive into akka streams: from the basics to a real-world scenario

Delegating work to actorsFlow[KinesisEvent]

.mapAsync(1) { event =>

(publisher ? Publish(event))

.mapTo[PublishCompleted]

}

Page 30: A dive into akka streams: from the basics to a real-world scenario

Flow[KinesisEvent]

.mapAsync(1) { event =>

(publisher ? Publish(event))

.mapTo[Future[PublishCompleted]]

.flatten

}

Page 31: A dive into akka streams: from the basics to a real-world scenario

Flow[ByteString]

.via(chunkBuffer)

.via(presenceEventFactory.asStream)

.via(persistentBuffer)

.via(kinesisPublisher)

.alsoTo(countEvents)

Page 32: A dive into akka streams: from the basics to a real-world scenario

Extra side-effects

val countEvents = Sink.foreach[Event] { _ => metricEventsPerTimeUnitOfSensor.mark() metricEventsPerTimeUnit.mark() }

Page 33: A dive into akka streams: from the basics to a real-world scenario

Automatic Fusion and Async Stages A stream is handled by 1 thread

NO CROSS-THREAD COMMUNICATIONS

NO PARALLELISM

FASTER CODE!

SLOWER CODE!

A boundary will split your stream on different threads

source .via(doSomething).async .via(doSomething).async .runWith(Sink.foreach(println))

Page 34: A dive into akka streams: from the basics to a real-world scenario

Materialized Valuesval sink: Sink[Any, Future[Done]] = Sink.ignore

.runWith(sink) is a shortcut for .toMat(sink)(Keep.Right).run

STREAM RUNObtain a materialized value per each stage

Page 35: A dive into akka streams: from the basics to a real-world scenario

Materialized Values Example: TestKit val myFlow = Flow[String].map { v => v.take(1) }

val (pub, sub) = TestSource.probe[String] .via(myFlow) .toMat(TestSink.probe[Any])(Keep.both) .run()

sub.request(1) pub.sendNext("Gathering") sub.expectNext("G")

Page 36: A dive into akka streams: from the basics to a real-world scenario

Stream Ending: Supervisioning

val flow = otherFlow .withAttributes ActorAttributes.supervisionStrategy { case _ => Supervision.resume } )

Page 37: A dive into akka streams: from the basics to a real-world scenario

Stream Ending: Supervisioning

RESUME

RESET

STOP

> drop failing elem > keep going

> drop failing elem > reset stage state > keep going

fail all the things!

Page 38: A dive into akka streams: from the basics to a real-world scenario

Other shapes

FAN OUT FAN IN WHATEVER

Page 39: A dive into akka streams: from the basics to a real-world scenario

Finally Got Reactive!

Page 40: A dive into akka streams: from the basics to a real-world scenario

In two months to production...

Memory Leaks Data Losses

Backpressure on the network Recovery mechanisms

Page 41: A dive into akka streams: from the basics to a real-world scenario

Key learnings

Actors aren’t sufficient to be reactive

Backpressure as a building block

Akka Streams API is rich

Page 42: A dive into akka streams: from the basics to a real-world scenario

THANK YOU!

Sleep more worry less