Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

105
Reactive Streams

Transcript of Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Page 1: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Reactive

Streams

Page 2: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Reactive

Streams

THEN Java Developer

LATER Enterprise Architect

NOW Scala Consultant

TWITTER @slavaschmidt

MAIL [email protected]

Page 3: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Stream

Page 4: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

A sequence of elements supporting

sequential and parallel aggregate

operations.

Java 8

Page 6: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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

Page 7: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Uses

Page 8: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

•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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams
Page 10: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams
Page 11: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

MEET ALICE AND BORIS

Page 12: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

MEET ALICE AND BORIS

Page 13: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java 6

Page 14: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java 7

Page 15: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams
Page 16: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams
Page 17: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams
Page 18: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java 8

Page 19: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

NAK (NACK)

Page 20: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Backpressure

Page 21: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Reactive Stream

Page 22: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

MEET ALICE AND BORIS

• Typical threads

• Do some work

• Exchange data

Page 23: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java IO

“Let’s move some data”

Page 25: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java IO

A PipedOutputStream

PipedInputStreamprotected byte buffer[];

B

Page 26: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java IOA PipedOutputStream BPipedInputStream

protected byte buffer[];

Page 27: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java IOA PipedOutputStream BPipedInputStream

Write

Block

Transfer

Block

Read

Block

Page 28: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Blocking is only a matter of time :(

Java IO

Page 33: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java NIO

“There is a better way”

Page 34: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java NIOA SinkChannel BSourceChannel

Write

Block

Transfer

BufferBuffer

Read

Block

Read

Fill

Page 35: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

“Choose how to fail”

Java NIO

Page 38: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

IO & NIO

Page 39: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

IO & NIO

Blocking

Dropping

or

Unbounded

or

Non-Determinism

OutOfMemory

Scalability

Page 40: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Solution

Backpressure

Page 41: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Solution

Backpressure

Dynamic Push/Pull

Fast Boris

Page 42: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Solution

Backpressure

Dynamic Push/Pull

Fast Alice

Page 43: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

BackpressureA BStream

Data

Demand

Data

Demand

Page 44: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Java 8

Page 45: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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 Scalable

Terminates on error

Page 49: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Problems

Synchronous

Non-Deterministic

Limited Scalable

Terminates on error

Page 50: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Problems

Synchronous

Non-Deterministic

Limited Scalable Terminates on error

Page 51: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Message Driven

Responsive

Elastic Resilient

Page 52: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Reactive

Message Driven

Responsive

Elastic Resilient

http://www.reactivemanifesto.org

Page 53: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Reactive Streams

… a standard for asynchronous stream processing with non-

blocking backpressure.

http://www.reactive-streams.org

Page 54: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

ParticipantsNetflix rxJava, rxScala, …OraclePivotal Spring Reactor

RedHat Vert.xTwitter

Typesafe Akka StreamsRatpack

Page 55: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Reactive Streams

• Semantics (Specification)

• API (Application Programming Interface)

• TCK (Technology Compatibility Kit)

Page 56: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Subscription

Subscription

subscribe

onSubscribe

Producer Subscriber

Page 58: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Streaming

request

Subscription

onNext

onComplete

onError

cancel

Subscriber

Page 59: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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

Akka Streams

Page 64: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Streams.create(alice).subscribe(borice)

Reactor Stream

Page 65: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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

Ratpack.io

Page 66: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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

RxReactiveStreams

Page 67: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

//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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Why should I care?

Page 69: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Because

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

Page 70: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Abstraction levels

Page 71: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Abstraction levels

Runnable & Thread

Page 72: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Abstraction levels

java.util.concurrent

Page 73: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Abstraction levels

Promise & Future

Page 74: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Abstraction levels

Actors

Page 75: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Abstraction levels

Streams

Page 76: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Abstraction levels

Page 77: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Interoperability

Page 78: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Shop Admin

Delivery

WebShop

Merchant

ADs Stats

Page 79: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Shop Admin

Delivery

WebShop

Merchant

ADs Stats

DB

REST

File System

Messaging

REST

Page 80: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Shop Admin(vert.x)

Delivery(Spring)

WebShop(ratpack.io)

Merchant(Akka)

ADs(Rx…)

Stats(Spray)

DB

REST

File System

Messaging

REST

Page 81: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Shop Admin(vert.x)

Delivery(Spring)

WebShop(ratpack.io)

Merchant(Akka)

ADs(Rx…)

Stats(Spray)

DB

Page 82: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Shop Admin(vert.x)

Data Flow

Backpressure

Delivery(Spring)

WebShop(ratpack.io)

Merchant(Akka)

ADs(Rx…)

Stats(Spray)

DB

Page 83: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Example Akka

Page 84: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Example Akka

Page 85: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Use Case

Price Correction System

Page 87: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Product schedulesCompetitors

Volatile sourcesAudit

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

Page 88: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

CompetitorsVolatile sources

Audit

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

Timer Scheduler

Page 89: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Volatile sourcesAudit

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

Timer Scheduler Robots

Page 90: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Audit

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

Validators

Timer Scheduler Robots

Page 91: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Historical trendsAlerts

Sales HeuristicsPricing Rules

Adjustments

ValidatorsLogger

Timer Scheduler Robots

Page 92: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Historical trendsAlerts

Pricing RulesAdjustments

Stock ValidatorsLogger

Timer Scheduler Robots

Page 93: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Historical trendsAlerts

Adjustments

Stock ValidatorsLogger

Timer Scheduler Robots

Pricing

Page 94: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Historical trendsAlerts

Stock ValidatorsLogger

Timer Scheduler Robots

Pricing Ruler

Page 95: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Historical trends

Stock ValidatorsLogger

Timer Scheduler Robots

Pricing Ruler Safety

Page 96: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Stock ValidatorsLogger

Timer Scheduler Robots

Pricing Ruler Safety

Archive

Page 97: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Stock

Validators

Logger

Timer Scheduler

Robots

Pricing

RulerSafety

Archive

Data Flow

Backpressure

Page 98: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Stock

Validators

Logger

Timer Scheduler

Robots

Pricing

RulerSafety

Archive

Data Flow

Backpressure

Page 100: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

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: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

24 cores

48 Gb

24 cores

48 Gb150 000 000

positions daily

Page 102: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Reactive Streams

Page 103: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Reactive Streams

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

Page 104: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Now I care!

Page 105: Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams

Thank you

@slavaschmidt

[email protected]