Upload
john-mcclean
View
274
Download
1
Embed Size (px)
Citation preview
Superchargeyour (reactive)
Streams
2
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classes
Visualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
A
A
A
P
P
P
Exchange
RTB Ad Cycle
100 ms
20,000,000,000+
6
multi-core
Race Conditions
Deadlocks
Contention
Non-Deterministic State
Thread StarvationLivelocks
8
Forecasting
9
Price / Volume Curve
Forecasting
11
Campaign Planning and Optimization
Query data across petabytes data
Accuracy & ResponsivenessBid Request RecordsPer Day
Impression RecordsPer Day
Viewability RecordsPer Day
20B 2B 2B
12
Speed
Indexing
13
14
15
Expectations
16
Reality
17
Phew!
18
Oops!
19
Why?
Why is it like this?
20
21
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classes
Visualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
22
Immutable
Declarative 23
Functional?
24
25
List<NormalizedElement> logs;
logs = logEntries.stream() .filter(log->log.elements.size()>100)
.flatMap(Log::elements) .map(this::normalize) .collect(Collectors.toList());
Functional
27
PriorityLevel speed = request.flatMap(Request::getUser) .flatMap(User::getPriority) .map(p->p.getLevel(service)) .orElse(PriorityLevel.SLOW);
Optional
functions.stream() .map(it -> it.apply(visit)) .flatMap(Collection::stream) .flatMap(v1 -> { functions2.stream() .map(it -> it.apply(time)) .flatMap(Collection::stream) .map(v2 -> join(v1,v2)) .collect(Collectors.toList()); }) .map(this::processJoinedEntry) .filter(Entry::isActive) .flatMap(Entry::subEntries) .flatMap(v3-> { functions3.stream() .map(it -> it.apply(time)) .flatMap(Collection::stream) .map(v4 -> join(v3,v4)) .collect(Collectors.toList());
});
Complexity
28
functions.stream() .map(it -> it.apply(visit)) .flatMap(Collection::stream) .flatMap(v1 -> { functions2.stream() .map(it -> it.apply(time)) .flatMap(Collection::stream) .map(v2 -> join(v1,v2)) .collect(Collectors.toList()); }) .map(this::processJoinedEntry) .filter(Entry::isActive) .flatMap(Entry::subEntries) .flatMap(v3-> { functions3.stream() .map(it -> it.apply(time)) .flatMap(Collection::stream) .map(v4 -> join(v3,v4)) .collect(Collectors.toList());
});
29
30
PURE
31
Easier to test
32
Optimizable
33
No side effects
Set<String> data;
public void populateData(){for(int i=0;i<100;i++){
String nextFile = prefix+i; data.add(transform(nextFile));
}}Side effects
34
PURE
35
public Set<String> populateData(){ Stream.iterate(0,i->i+1) .limit(100) .map(i->"prefix"+i) .map(this::transform) .collect(Collectors.toSet());}
36
Stream.iterate(0,i->i+1) .limit(100) .map(i->"prefix"+i) .map(this::transform) .collect(Collectors.toSet());
Paralle
l
37
Stream.iterate(0,i->i+1) .limit(100) .parallel() .map(i->"prefix"+i) .map(this::transform) .collect(Collectors.toSet());
Paralle
lize
Testable?38
Set<String> data;
public void populateData() {for(int i=0;i<100;i++){
String nextFile = prefix+i; data.add(transform(nextFile));
}}
39
Traditional Imperative Java
Java 8
Mutable Immutable
Stateful Stateless
Concurrent app?40
public Set<String> populateData(){ return Stream.iterate(0,i->i+1) .limit(100) .map(i->"prefix"+i) .map(this::transform) .collect(Collectors.toSet());}
Set<String> data;
public void populateData() {for(int i=0;i<100;i++){
String nextFile = prefix+i; data.add(transform(nextFile));
}}
41
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classes
Visualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
42
Microservice
example
Read / Transform / Write
43
Stream.generate(this::pollS3). .map(this::processAndTransform) .map(this::storeInS3)
44
ScheduleStream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3)
45
StreamUtils.scheduleFixedDelay(Stream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3), 20_000, executor))
Schedule
46
StreamUtils.scheduleFixedDelay(Stream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3), 20_000, executor))
Schedule
47
48
49
50
StreamUtils.scheduleFixedDelay(Stream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3), 20_000, executor))
A Snag
51
public Data pollS3() throws AmazonServiceException, AmazonClientException
52
53
54
55
StreamUtils.scheduleFixedDelay(Stream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3), 20_000, executor))
Error Handling
56
StreamUtils.scheduleFixedDelay(StreamUtils.recover(Stream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3),e->false), 20_000,
executor))
Error Handling
57
StreamUtils.scheduleFixedDelay(StreamUtils.recover(Stream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3),e->false), 20_000,
executor))
Error Handling
58
59
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classesVisualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
60
StreamUtils.scheduleFixedDelay(StreamUtils.recover(Stream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3),e->false), 20_000,
executor))
Read / Transform / Write
61
Stream.generate(this::pollS3). .map(this::processAndTransform) .map(this::storeInS3)
62
ReactiveSeq.generate(this::pollS3). .map(this::processAndTransform) .map(this::storeInS3);
Extended Stream
63
ReactiveSeq.generate(this::pollS3). .map(this::processAndTransform) .map(this::storeInS3)
.recover(e->false) .scheduleFixedDelay(20_000,executor)
Extension methods
64
65
66
Seq
67
Stream
ReactiveSeq
68
uential69
Seq.of("a","b","c","d") .map(String::toUpperCase) .zipWithIndex() .filter(t->t.v2%2==0) .sliding(3) .duplicate();
interface Seq extends Stream { }
Seq.of(1, 2, 4)
.rightOuterJoin(Seq.of(1, 2, 3), (a, b) -> a == b);
Seq
70
ReactiveSeq.of(1,2,3) .map(this::load) .recover(e->"default value") .retry(this::unreliableMethod);
Error HandlingError handling
71
ReactiveSeq.of(1,2,3,4) .futureOperations(Executors.newFixedThreadPool(1)) .forEach(this::expensiveOp);
Asynchronous execution
Error handlingAsync execution
Scheduling
72
ReactiveSeq.of(1,2,3) .schedule("* * * * * ?", Executors.newScheduledThreadPool(1)) .connect() .debounce(1, TimeUnit.SECONDS) .forEach(System.out::println);
Error handlingAsync executionScheduling
73
ReactiveSeq<Integer> stream = ReactiveSeq.of(1,2,3,4);Subscription s = stream.forEachXEvents(2, System.out::println, System.err::println, ()->System.out.println("complete")); s.request(2);
Subscriptions& Events
Error handlingAsync executionSchedulingSubscriptions
reactive-streams
74
interface ReactiveSeq extends Seq, Stream, Publisher { }
SeqSubscriber<Integer> sub = SeqSubscriber.subscriber(); Flux.just(1,2,3,4) .map(i->i*2) .subscribe(sub); ReactiveSeq<Integer> connected = sub.stream();
Error handlingAsync executionSchedulingSubscriptionsreactive-streams
75
Parallel
76
new LazyReact().of(1,2,3,4) .map(this::load) .forEach(this::save);
interface LazyFutureStream extends ReactiveSeq, Seq, Stream, Publisher { }
Error handlingAsync executionSchedulingSubscriptionsreactive-streamsFuture streams
Optional
Stream
CompletableFuture
ReactiveSeqLazyFutureStream
ListX
FutureW
Maybe
Try
Xor
Eval
SetX
PStackXPVectorX
PSetX
78
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classes
Visualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
JDK Sequential Stream
79
.map(e -> e*100)
.forEach(System.out::println)
.filter(e -> e<551)
Stream.of(6,5,1,2)
Sequential Stream
80
first stage(map)
second stage(filter)
terminal stage (forEach)
Sequential Stream
81
first stage(map)
second stage(filter)
terminal stage (forEach)
500
2
1
5 600
JDK Parallel Stream
82
.map(e -> e*100)
.forEach(System.out::println)
.filter(e -> e<551)
Stream.of(6,5,1,2)
.parallel()
Parallel Stream
83
terminal stage
(forEach)
first stage(map)
second stage(filter)
first stage(map)
second stage(filter)
first stage(map)
second stage(filter)
first stage(map)
second stage(filter)
elements 1..n
elements 1..n/2
elements n/2..n
elements 1..n/4
elements n/4..n/2
elements n/2..3/4n
elements 3/4n..n
84
Alternatives?
85
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classes
Visualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
86
CPU
Sequential Stream
87
first stage(map)
second stage(filter)
terminal stage (forEach)
88
first stage(map)
second stage(filter)
terminal stage (forEach)core 1
first stage(map)
second stage(filter)
terminal stage (forEach)core 2
first stage(map)
second stage(filter)
terminal stage (forEach)core 3
first stage(map)
second stage(filter)
terminal stage (forEach)core 4
Parallel Pipelines
Sequential Streams
89
Parallel Pipelinesfirst stage
(map)second stage
(filter)terminal stage
(forEach)core 1 third stage(target thread)
first stage(map)
second stage(filter)
terminal stage (forEach)core 2 third stage
(target thread)
first stage(map)
second stage(filter)
terminal stage (forEach)core 3 third stage
(target thread)
first stage(map)
second stage(filter)
terminal stage (forEach)core 4 third stage
(target thread)
90
ReactiveSeq
Sequential Stream
91
.map(e -> e*100)
.forEach(System.out::println)
.filter(e -> e<551)
ReactiveSeq.of(6,5,1,2)
.futureOperations(executor)
92
93
94
95
96
97
98
Performance
99
Low
er is
bet
ter
100
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classes
Visualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
101
I/O
102
first stage(map)
second stage(filter)
terminal stage (forEach)
future 1
future 2
future 3
future 4
future 5
future 6
future 7
future 8
future 9
future 10 future
11
Concurrent tasks
103
Future
Async I/O CompletableFuture
104
.thenApply(e -> e*100)
CompletableFuture.supplyAsync(this::load)
.thenAccept(e ->{ if(e<551) System.out.println(e); } );
Async I/O
105
.map(e -> e*100)
.peek(System.out::println)
.filter(e -> e<551)
FutureW.ofSupplier(this::load)
106
FutureStream
Stream of CompletableFutures
107
.map(f ->f.thenApply(e-> e*100))
.peek(f-> f.thenAccept(System.out::println))
Stream.of(6,5,1,2) .map(e->CompletableFuture.supplyAsync(this::load,executor))
.filter( here be dragons)
.collect(Collectors.toList()) //join each elem
Stream of Futures
108
.map(f ->f.map(e-> e*100))
Stream.of(6,5,1,2)
.map(e->FutureW.ofSupplier(this::load,executor))
.peek(f-> f.peek(System.out::println)) .collect(Collectors.toList()) //join each
elem
.filter(here be dragons)
FutureStream
109
.map(e -> e*100)
.forEach(System.out::println)
.filter(e -> e<551)
new LazyReact(executor).of(6,5,1,2).map(this::loadData)
110
111
112
Performance
113
Low
er is
bet
ter
Indexing
114
Reactive Indexing Architecture
115
116
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classes
Visualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
117
Queues
118
Create a Queue
119
Wrapped Queue Type : Bounded Blocking Queue
QueueFactories. <Data>boundedQueue(1_000) .build();
Reading from Queues
120
Queue<Data> transfer; transfer.stream() .forEach(this::process);
Writing to Queues
121
Queue<Data> transfer;
new LazyReact(executor).generate(this::loadNext) .map(this::process) .forEach(data->transfer.offer(data));
Backpressure - FULL
122
Backpressure - EMPTY
123
124
125
126
127
128
129
Concurrency is hard!
Does Java 8 help?
Extending Streams
Static methods Extension classes
Visualizing Streams
Parallel Streams
CPU Bound I/O Bound
Connecting Streams
A consistent Stream based Architecture
Reactive Indexing Architecture
130
131
Summary
Easier to parellize?
132
public Set<String> populateData(){ return Stream.iterate(0,i->i+1) .limit(100) .map(i->"prefix"+i) .map(this::transform) .collect(Collectors.toSet());}
Set<String> data;
public void populateData() {for(int i=0;i<100;i++){
String nextFile = prefix+i; data.add(transform(nextFile));
}}
133
StreamUtils.scheduleFixedDelay(StreamUtils.recover(Stream.generate(this::pollS3).
.map(this::processAndTransform) .map(this::storeInS3),e->false), 20_000,
executor))
Extension methods have limits
134
Richer sequential API
Parallelism can be layered back in
135
.map(e -> e*100)
.forEach(System.out::println)
.filter(e -> e<551)
new LazyReact(executor).of(6,5,1,2).map(this::loadData)
136
Transfer queues for advanced connections
137
Check outcyclops-react.io
Thank You.
139
Pics:Ducks and Cat by https://www.flickr.com/photos/11325321@N08/ under CC2