reactive streams. slava schmidt

105
Reactiv e Stream s

Upload: alina-dolgikh

Post on 12-Aug-2015

111 views

Category:

Software


3 download

TRANSCRIPT

Page 1: Reactive streams. Slava Schmidt

Reactive

Streams

Page 2: Reactive streams. Slava Schmidt

THENJava DeveloperLATEREnterprise ArchitectNOWScala Consultant

TWITTER@[email protected]

Reactive

Streams

Page 3: Reactive streams. Slava Schmidt

Stream

Page 4: Reactive streams. Slava Schmidt

A stream can be defined as a sequence of

data.

A powerful concept that greatly simplifies I/

O operations.

Java 5/6/7

Page 5: Reactive streams. Slava Schmidt

A sequence of elements

supporting sequential and

parallel aggregate operations.

Java 8

Page 6: Reactive streams. Slava Schmidt

•sequence of data or instructions•hot or cold•bounded or unbounded•focus on data transfer and/or transformation

Page 7: Reactive streams. Slava Schmidt

Uses

Page 8: Reactive streams. Slava Schmidt

•bulk data transfer•batch processing of large data sets•micro-batching•real-time data sources•embedded data-processing•monitoring and analytics•metrics, statistics composition •event processing•error handling

Page 9: Reactive streams. Slava Schmidt
Page 10: Reactive streams. Slava Schmidt
Page 11: Reactive streams. Slava Schmidt

MEETALICE AND BORIS

Page 12: Reactive streams. Slava Schmidt

MEETALICE AND BORIS

Page 13: Reactive streams. Slava Schmidt

Java 6

Page 14: Reactive streams. Slava Schmidt

Java 7

Page 15: Reactive streams. Slava Schmidt
Page 16: Reactive streams. Slava Schmidt
Page 17: Reactive streams. Slava Schmidt
Page 18: Reactive streams. Slava Schmidt

Java 8

Page 19: Reactive streams. Slava Schmidt

NAK (NACK)

Page 20: Reactive streams. Slava Schmidt

Backpressure

Page 21: Reactive streams. Slava Schmidt

Reactive Stream

Page 22: Reactive streams. Slava Schmidt

MEETALICE AND BORIS

•Typical threads

•Do some work

•Exchange data

Page 23: Reactive streams. Slava Schmidt

Direct Callsprivate static final SThread alice = new SThread("RS-Alice") { @Override public void swap(int count) { super.swap(count); borice.swap(count); } };

private static final SThread borice = new SThread("RS-Borice") { @Override public void run() { while (!stopped()) { SwapEnvironment.work(); } } @Override public void swap(int count) { super.swap(count); } };

Page 24: Reactive streams. Slava Schmidt

Java IO

“Let’s move some data”

Page 25: Reactive streams. Slava Schmidt

Java IO

A PipedOutputStream

PipedInputStreamprotected byte buffer[];

B

Page 26: Reactive streams. Slava Schmidt

Java IOA PipedOutputStream BPipedInputStream

protected byte buffer[];

Page 27: Reactive streams. Slava Schmidt

Java IOA PipedOutputStream BPipedInputStream

Write

Block

Transfer

Block

Read

Block

Page 28: Reactive streams. Slava Schmidt

Java IOval alice = new SThread("RS-Alice") { override def swap(n: Int) { super.swap(n) for (i <- 0 to n * rateA) out.write(Env.BEER) }}

val borice = new SThread("RS-Borice") { override def swap(n: Int) { super.swap(n) for (i <- 0 to n * rateB) in.read() }}

val out = new PipedOutputStream()val in = new PipedInputStream(out, size)

Page 29: Reactive streams. Slava Schmidt

Java IOval alice = new SThread("RS-Alice") { override def swap(n: Int) { super.swap(n) for (i <- 0 to n * rateA) out.write(Env.BEER) }}

val borice = new SThread("RS-Borice") { override def swap(n: Int) { super.swap(n) for (i <- 0 to n * rateB) in.read() }}

val out = new PipedOutputStream()val in = new PipedInputStream(out, size)

INCREASE

Page 30: Reactive streams. Slava Schmidt

Java IOval alice = new SThread("RS-Alice") { override def swap(n: Int) { super.swap(n) for (i <- 0 to n * rateA) out.write(Env.BEER) }}

val borice = new SThread("RS-Borice") { override def swap(n: Int) { super.swap(n) for (i <- 0 to n * rateB) in.read() }}

val out = new PipedOutputStream()val in = new PipedInputStream(out, size)

INCREASE

Page 31: Reactive streams. Slava Schmidt

Java IOval alice = new SThread("RS-Alice") { override def swap(n: Int) { super.swap(n) for (i <- 0 to n * rateA) out.write(Env.BEER) }}

val borice = new SThread("RS-Borice") { override def swap(n: Int) { super.swap(n) for (i <- 0 to n * rateB) in.read() }}

val out = new PipedOutputStream()val in = new PipedInputStream(out, size)

INCREASE

Page 32: Reactive streams. Slava Schmidt

Blocking is only a matter of time :(

Java IO

Page 33: Reactive streams. Slava Schmidt

Java NIO“There is a better way”

Page 34: Reactive streams. Slava Schmidt

Java NIOA SinkChannel BSourceChannel

Write

Block

Transfer

BufferBuffer

Read

Block

Read

Fill

Page 35: Reactive streams. Slava Schmidt

Java NIOval alice = new SThread("RS-Alice") { override def swap(n: Int) { val cnt = n * rateA val buffer = ByteBuffer.allocate(cnt) buffer.put(Vector.fill(cnt)(BEER).toArray) buffer.flip() val written = sinkChannel.write(buffer) super.swap(written) }}

val borice = new SThread("RS-Borice") { override def swap(n: Int) { val buffer = ByteBuffer.allocate(n * rateB) val cnt = sourceChannel.read(buffer) super.swap(cnt) }}

val pipe = Pipe.open()val sinkChannel = pipe.sinkval sourceChannel = pipe.sourcesourceChannel.configureBlocking(true) sinkChannel.configureBlocking(false)

BLOCKING

Page 36: Reactive streams. Slava Schmidt

Java NIOval alice = new SThread("RS-Alice") { override def swap(n: Int) { val cnt = n * rateA val buffer = ByteBuffer.allocate(cnt) buffer.put(Vector.fill(cnt)(BEER).toArray) buffer.flip() val written = sinkChannel.write(buffer) super.swap(written) }}

val borice = new SThread("RS-Borice") { override def swap(n: Int) { val buffer = ByteBuffer.allocate(n * rateB) val cnt = sourceChannel.read(buffer) super.swap(cnt) }}

val pipe = Pipe.open()val sinkChannel = pipe.sinkval sourceChannel = pipe.sourcesourceChannel.configureBlocking(false) sinkChannel.configureBlocking(false)

NON-BLOCKING

Page 37: Reactive streams. Slava Schmidt

“Choose how to fail”

Java NIO

Page 38: Reactive streams. Slava Schmidt

IO & NIO

Page 39: Reactive streams. Slava Schmidt

IO & NIO

Blocking

Dropping

or

Unbounded

or

Non-Determinism

OutOfMemory

Scalability

Page 40: Reactive streams. Slava Schmidt

Solution

Backpressure

Page 41: Reactive streams. Slava Schmidt

Solution

Backpressure

Dynamic Push/Pull

Fast Boris

Page 42: Reactive streams. Slava Schmidt

Solution

Backpressure

Dynamic Push/Pull

Fast Alice

Page 43: Reactive streams. Slava Schmidt

BackpressureA BStream

Data

Demand

Data

Demand

Page 44: Reactive streams. Slava Schmidt

Java 8

Page 45: Reactive streams. Slava Schmidt

Java 8public class ConsumerBorice extends SThread implements Consumer<byte[]> { public ConsumerBorice(String name) { super(name); } @Override public Consumer andThen(Consumer after) { return after; } @Override public void accept(byte[] bytes) { super.swap(bytes.length); } }

Page 46: Reactive streams. Slava Schmidt

Java 8private static final ConsumerBorice borice =

new ConsumerBorice("RS-Borice") { public void swap(int count) { }};

private static final SThread alice = new SThread ("RS-Alice") { byte[] items(int count) { byte[] result = new byte[count]; Arrays.fill(result, Env.BEER()); return result; } public void swap(int count) { Stream.of(items(count)).parallel() .filter(s -> s.equals(Env.BEER())) .forEach(borice); super.swap(count); } };

Page 47: Reactive streams. Slava Schmidt

Java 8private static final ConsumerBorice borice =

new ConsumerBorice("RS-Borice") { public void swap(int count) { }};

private static final SThread alice = new SThread ("RS-Alice") { byte[] items(int count) { byte[] result = new byte[count]; Arrays.fill(result, Env.BEER()); return result; } public void swap(int count) { Stream.of(items(count)).parallel() .filter(s -> s.equals(Env.BEER())) .forEach(borice); super.swap(count); } }; transformation

static push (or pull)

or sequential

Page 48: Reactive streams. Slava Schmidt

Java 8private static final ConsumerBorice borice =

new ConsumerBorice("RS-Borice") { public void swap(int count) { }};

private static final SThread alice = new SThread ("RS-Alice") { byte[] items(int count) { byte[] result = new byte[count]; Arrays.fill(result, Env.BEER()); return result; } public void swap(int count) { Stream.of(items(count)).parallel() .filter(s -> s.equals(Env.BEER())) .forEach(borice); super.swap(count); } }; Synchronous

Non-Deterministic

Limited Scalability

Terminates on error

Page 49: Reactive streams. Slava Schmidt

Problems

Synchronous

Non-Deterministic

Limited Scalability

Terminates on error

Page 50: Reactive streams. Slava Schmidt

Problems

Synchronous

Non-Deterministic

Limited Scalability Terminates on error

Page 51: Reactive streams. Slava Schmidt

Message Driven

Responsive

Elastic Resilient

Page 52: Reactive streams. Slava Schmidt

Reactive

Message Driven

Responsive

Elastic Resilient

http://www.reactivemanifesto.org

Page 53: Reactive streams. Slava Schmidt

Reactive Streams

… a standard for asynchronous stream processing with non-

blocking backpressure.

http://www.reactive-streams.org

Page 54: Reactive streams. Slava Schmidt

ParticipantsNetflix rxJava, rxScala, …

Oracle

Pivotal Spring Reactor

RedHat Vert.x

Twitter

Typesafe Akka Streams

Ratpack

Page 55: Reactive streams. Slava Schmidt

Reactive Streams

• Semantics (Specification)

• API (Application Programming Interface)

• TCK (Technology Compatibility Kit)

Page 56: Reactive streams. Slava Schmidt

APIpublic interface Publisher<T> { void subscribe(Subscriber<? super T> var1); }

public interface Subscriber<T> { void onSubscribe(Subscription var1); void onNext(T var1); void onError(Throwable var1); void onComplete(); }

public interface Subscription { void request(long var1); void cancel(); }

Page 57: Reactive streams. Slava Schmidt

Subscription

Subscription

subscribe

onSubscribe

Producer Subscriber

Page 58: Reactive streams. Slava Schmidt

Streaming

request

Subscription

onNext

onComplete

onError

cancel

Subscriber

Page 59: Reactive streams. Slava Schmidt

trait BytePublisher extends Publisher[Byte] { var subscriber: Subscriber[_ >: Byte] = _ override def subscribe(subscriber: Subscriber[_ >: Byte]) { this.subscriber = subscriber }}

val alice = new SThread("RS-Alice") with BytePublisher {

override def swap(n: Int) { for { i <- 1 to n } subscriber.onNext(Env.BEER) super.swap(n) }

}

Publisher

Page 60: Reactive streams. Slava Schmidt

trait ByteSubscriber[T >: Byte] extends Subscriber[T] { var subscription: Subscription = _ override def onSubscribe(subscription: Subscription) { this.subscription = subscription } override def onError(t: Throwable) { } override def onComplete() { }}

val borice = new SThread(“RS-Borice") with ByteSubscriber[Byte]{

def onNext(t: Byte) { super.swap(1) }}

Subscriber

Page 61: Reactive streams. Slava Schmidt

val borice = new SThread(“RS-Borice") with ByteSubscriber[Byte]{ alice.subscribe(this) override def swap(n: Int) { subscription.request(n) } def onNext(t: Byte) { super.swap(1) }}

Right Subscriber

Page 62: Reactive streams. Slava Schmidt

val alice = new SThread("RS-Alice") with BytePublisher { override def swap(n: Int) { val cnt = math.min(n, counter.get()) counter.addAndGet(-cnt) for { i <- 1 to cnt } subscriber.onNext(Env.BEER) super.swap(n) }}

Right Publishertrait BytePublisher extends Publisher[Byte] { var subscriber: Subscriber[_ >: Byte] = _ var subscription: Subscription = _ val counter = new AtomicInteger(0) def request(l: Long): Unit = { counter.addAndGet(l.toInt) } override def subscribe(subscriber: Subscriber[_ >: Byte]) { this.subscription = new ByteSub(this) this.subscriber = subscriber subscriber.onSubscribe(this.subscription) }}

Page 63: Reactive streams. Slava Schmidt

implicit val mat = FlowMaterializer()(system)Source(alice).runWith(Sink(borice))

Akka Streams

Page 64: Reactive streams. Slava Schmidt

Streams.create(alice).subscribe(borice)

Reactor Stream

Page 65: Reactive streams. Slava Schmidt

ratpack.stream.Streams.buffer(alice).subscribe(borice)

Ratpack.io

Page 66: Reactive streams. Slava Schmidt

import rx.RxReactiveStreams._ subscribe(toObservable(alice), borice)

RxReactiveStreams

Page 67: Reactive streams. Slava Schmidt

//vert.x 3.0 - only supports Streams[Buffer] val rws = ReactiveWriteStream.writeStream()rws.subscribe(borice)val rrs = ReactiveReadStream.readStream() alice.subscribe(rrs)val pump = Pump.pump(rrs, rws)pump.start()

Vert.X

Page 68: Reactive streams. Slava Schmidt

Why should I care?

Page 69: Reactive streams. Slava Schmidt

Because

•Simplifies reactive programming•Rises program’s abstraction level•May be future JDK standard

Page 70: Reactive streams. Slava Schmidt

Abstraction levels

Page 71: Reactive streams. Slava Schmidt

Abstraction levels

Runnable & Thread

Page 72: Reactive streams. Slava Schmidt

Abstraction levels

java.util.concurrent

Page 73: Reactive streams. Slava Schmidt

Abstraction levels

Promise & Future

Page 74: Reactive streams. Slava Schmidt

Abstraction levels

Actors

Page 75: Reactive streams. Slava Schmidt

Abstraction levels

Streams

Page 76: Reactive streams. Slava Schmidt

Abstraction levels

Page 77: Reactive streams. Slava Schmidt

Interoperability

Page 78: Reactive streams. Slava Schmidt

Shop Admin

Delivery

WebShop

Merchant

ADs Stats

Page 79: Reactive streams. Slava Schmidt

Shop Admin

Delivery

WebShop

Merchant

ADs Stats

DB

REST

File System

Messaging

REST

Page 80: Reactive streams. Slava Schmidt

Shop Admin(vert.x)

Delivery(Spring)

WebShop(Akka)

Merchant(ratpack.io)

ADs(Rx…)

Stats(Spray)

DB

REST

File System

Messaging

REST

Page 81: Reactive streams. Slava Schmidt

Shop Admin(vert.x)

Delivery(Spring)

WebShop(Akka)

Merchant(ratpack.io)

ADs(Rx…)

Stats(Spray)

DB

Page 82: Reactive streams. Slava Schmidt

Shop Admin(vert.x)

Data Flow

Backpressure

Delivery(Spring)

WebShop(Akka)

Merchant(ratpack.io)

ADs(Rx…)

Stats(Spray)

DB

Page 83: Reactive streams. Slava Schmidt

Example Akka

Page 84: Reactive streams. Slava Schmidt

Example Akka

Page 85: Reactive streams. Slava Schmidt

val display = { def ellipse (i: Input) = setColor(i).fillOval(i(3), i(4), i(5), i(6)) def rect (i: Input) = setColor(i).fillRect(i(3), i(4), i(5), i(6)) val logics: Seq[(Input) => Unit] = Seq(ellipse, rect) def rnd = Random.nextInt(255) val timer = Source(0.seconds, 1.second, () => rnd ) val randoms = Source { () => Some(rnd) } val functions = timer map { i => logics(i % logics.size) } val display = functions map { f => val groups = randoms.take(7) val params = groups.fold(List.empty[Int])((l, i) => i :: l) for { p <- params } f(p) } display} def start = { display.runWith(BlackholeSink)}

Example Akka

Page 86: Reactive streams. Slava Schmidt

Use Case

Price Correction System

Page 87: Reactive streams. Slava Schmidt

Product schedulesCompetitors

Volatile sourcesAudit

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

Page 88: Reactive streams. Slava Schmidt

CompetitorsVolatile sources

Audit

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

Timer Scheduler

Page 89: Reactive streams. Slava Schmidt

Volatile sourcesAudit

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

Timer Scheduler Robots

Page 90: Reactive streams. Slava Schmidt

Audit

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

Validators

Timer Scheduler Robots

Page 91: Reactive streams. Slava Schmidt

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

ValidatorsLogger

Timer Scheduler Robots

Page 92: Reactive streams. Slava Schmidt

Historical trendsAlerts

Pricing RulesAdjustments

Stock ValidatorsLogger

Timer Scheduler Robots

Page 93: Reactive streams. Slava Schmidt

Historical trendsAlerts

Adjustments

Stock ValidatorsLogger

Timer Scheduler Robots

Pricing

Page 94: Reactive streams. Slava Schmidt

Historical trendsAlerts

Stock ValidatorsLogger

Timer Scheduler Robots

Pricing Ruler

Page 95: Reactive streams. Slava Schmidt

Historical trends

Stock ValidatorsLogger

Timer Scheduler Robots

Pricing Ruler Safety

Page 96: Reactive streams. Slava Schmidt

Stock ValidatorsLogger

Timer Scheduler Robots

Pricing Ruler Safety

Archive

Page 97: Reactive streams. Slava Schmidt

Stock

Validators

Logger

Timer Scheduler

Robots

Pricing

RulerSafety

Archive

Data Flow

Backpressure

Page 98: Reactive streams. Slava Schmidt

val schedules = Flow[Date] mapConcat generateSchedules val robots = Flow[Schedule] map scrape

val validations = Flow[ScrapeResult] map { site => logSite(site) validate(site)}

val pricing = Flow[Validation] map checkPrice

val stock = Flow[Validation] map checkStock

val ruler = Flow[(Price, Stock)] map applyRule

val safety = Flow[Rule] map checkSafety

val zip = Zip[Price, Stock] val split = Broadcast[Validation]

Page 99: Reactive streams. Slava Schmidt

Stock

Validators

Logger

Timer Scheduler

Robots

Pricing

RulerSafety

Archive

Data Flow

Backpressure

Page 100: Reactive streams. Slava Schmidt

val timer = Source(0.seconds, 1.minute, () => now) val archive = ForeachSink[SafetyCheck] { logRule }

val graph = FlowGraph { implicit builder => timer ~> schedules ~> robots ~> validations ~> split split ~> stock ~> zip.right split ~> pricing ~> zip.left ~> ruler ~> safety ~> archive} graph.run()

Page 101: Reactive streams. Slava Schmidt

24 cores

48 Gb

24 cores

48 Gb150 000 000

positions daily

Page 102: Reactive streams. Slava Schmidt

Reactive Streams

Page 103: Reactive streams. Slava Schmidt

Reactive Streams

•Simplify reactive programming•Rise program’s abstraction level•May be future JDK standard

Page 104: Reactive streams. Slava Schmidt

Now I care!

Page 105: Reactive streams. Slava Schmidt

Thank you

https://github.com/slavaschmidt/reactive_streams_talk

@slavaschmidt

[email protected]