Contenu connexe Similaire à Spring Framework 5.0による Reactive Web Application #JavaDayTokyo (20) Plus de Toshiaki Maki (20) Spring Framework 5.0による Reactive Web Application #JavaDayTokyo1. ‹#›© 2016 Pivotal Software, Inc. All rights reserved. ‹#›© 2017 Pivotal Software, Inc. All rights reserved.
Spring Framework 5.0
Reactive Web Application
Toshiaki Maki (@making)
2016-05-17 Java Day Tokyo 2017
2. © 2017 Pivotal Software, Inc. All rights reserved.
Who am I ?
• Toshiaki Maki (@making) https://blog.ik.am
• Sr. Solutions Architect @Pivotal
• Spring Framework 💖
• Cloud Foundry 💖
bit.ly/hajiboot2
4. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive???
"In a nutshell reactive programming is about
non-blocking, event-driven applications that
scale with a small number of threads with
backpressure as a key ingredient that remains
to ensure producers do not overwhelm
consumers"
- Rossen Stoyanchev
5. © 2017 Pivotal Software, Inc. All rights reserved.
Sync / Blocking
https://speakerdeck.com/simonbasle/reactor-3
6. © 2017 Pivotal Software, Inc. All rights reserved.
Sync / Blocking
https://speakerdeck.com/simonbasle/reactor-3
I/O
main thread processing
resumes
7. © 2017 Pivotal Software, Inc. All rights reserved.
Sync / Blocking
https://speakerdeck.com/simonbasle/reactor-3
I/O
main thread processing
resumes
😴 app does nothing
8. © 2017 Pivotal Software, Inc. All rights reserved.
Async & Blocking
https://speakerdeck.com/simonbasle/reactor-3
9. © 2017 Pivotal Software, Inc. All rights reserved.
Async & Blocking
https://speakerdeck.com/simonbasle/reactor-3
main thread wait &
join
10. © 2017 Pivotal Software, Inc. All rights reserved.
Async & Blocking
https://speakerdeck.com/simonbasle/reactor-3
main thread wait &
join
complex
new
threads,
costly
11. © 2017 Pivotal Software, Inc. All rights reserved.
Async & Non-Blocking
12. © 2017 Pivotal Software, Inc. All rights reserved.
Async & Non-Blocking
https://speakerdeck.com/simonbasle/reactor-3
Event
Loop
chunks
processing
in non-blocking
13. © 2017 Pivotal Software, Inc. All rights reserved.
Blocking + Thread pools (Servlet)
HTTP request
HTTP response
📖⏳
⚙⏳
✍⏳
Thread
14. © 2017 Pivotal Software, Inc. All rights reserved.
Non-blocking and event-loop (Netty)
IO Selector Thread Worker Threads
🔄
📖⚙ ⚙ ✍
✍ ⚙ 📖⚙
📖 ✍ ✍ ⚙
⚙ ✍ 📖 📖🔄
🔄
🔄
🔄
15. © 2017 Pivotal Software, Inc. All rights reserved.
Non-blocking and event-loop (Netty)
IO Selector Thread Worker Threads
🔄
📖⚙ ⚙ ✍
✍ ⚙ 📖⚙
📖 ✍ ✍ ⚙
⚙ ✍ 📖 📖🔄
🔄
🔄
🔄
https://github.com/backpaper0/httpserver
16. © 2017 Pivotal Software, Inc. All rights reserved.
Use Case: Remote call with latency
☁💻
https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
17. © 2017 Pivotal Software, Inc. All rights reserved.
Use Case: Remote call with latency
☁💻
https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
🐌
18. © 2017 Pivotal Software, Inc. All rights reserved.
Use Case: Remote call with latency
☁💻
https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
🐌
19. © 2017 Pivotal Software, Inc. All rights reserved.
Use Case: Serve a lot of slow clients
https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
📱📱 📱📱 📱📱 📱📱 📱📱 📱📱
20. © 2017 Pivotal Software, Inc. All rights reserved.
Use Case: Push message to client
https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
💻 💬💬💬
Server-Sent Events
WebSocket
RabbitMQ
Apache Kafka
∞
21. © 2017 Pivotal Software, Inc. All rights reserved.
Other Use Cases
•Live (continuous) database queries
•UI event handling (Android)
•Big Data
•Real Time Analytics
•HTTP/2
22. © 2017 Pivotal Software, Inc. All rights reserved.
Going Reactive
More for scalability and stability than for speed
23. © 2017 Pivotal Software, Inc. All rights reserved.
blocking ====> event-based
public class IAmBlocking {
public void blockingCode() {
String a = callRemoteA();
String b = callRemoteB();
String c = callRemoteC();
String d = callRemoteD();
System.out.println(a+" "+b+" "+c+" "+d);
}
}
😅
24. © 2017 Pivotal Software, Inc. All rights reserved.
blocking ====> event-based
public class AmIReactive {
public void amIReallyReactive() {
callRemoteA(a -> {
callRemoteB(b -> {
callRemoteC(c -> {
callRemoteD(d -> println(a+" "+b+" "+c+" "+d),
exd -> exd.printStackTrace())
}, exc -> exc.printStackTrace())
}, exb -> exb.printStackTrace()
}, exa -> exa.printStackTrace());}}
😕
25. © 2017 Pivotal Software, Inc. All rights reserved.
public class IAmReactive {
public void iAmReallyReactive() {
when(callRemoteA(), callRemoteB(),
callRemoteC(), callRemoteD())
.doOnError(e -> e.printStakcTrace())
.subscribe(t -> // Tuple4<A, B, C, D>
println(t.t1 +" "+t.t2+" "+t.t3+" "+t.t4));
blocking ====> event-based
😀
27. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive Streams
•Standard interfaces for asynchronous stream
processing with non-blocking back pressure
•De-facto standard for interoperability
between reactive libraries
•Implemented by
http://www.reactive-streams.org/
28. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive Streams
•Standard interfaces for asynchronous stream
processing with non-blocking back pressure
•De-facto standard for interoperability
between reactive libraries
•Implemented by
http://www.reactive-streams.org/
RxJava 2 Reactor Akka Streams
29. ‹#›© 2016 Pivotal Software, Inc. All rights reserved.
Reactive Streams has 4 interfaces
public interface Publisher<T> {
void subscribe(Subscriber<? super T> s);
}
public interface Subscription {
void request(long n);
void cancel();
}
public interface Subscriber<T> {
void onSubscribe(Subscription s);
void onNext(T t);
void onError(Throwable t);
void onComplete();
}
public interface Processor<T, R> extends
Publisher<T>, Subscriber<R> {}
30. © 2017 Pivotal Software, Inc. All rights reserved.
Publisher Subscriber
Data Flow
31. © 2017 Pivotal Software, Inc. All rights reserved.
Publisher Subscriber
subscribe
Data Flow
32. © 2017 Pivotal Software, Inc. All rights reserved.
Publisher Subscriber
request(n)
Backpressure
Data Flow
33. © 2017 Pivotal Software, Inc. All rights reserved.
Publisher Subscriber
Backpressure
onNext(data)
onNext(data)
onNext(data)
Data Flow
34. © 2017 Pivotal Software, Inc. All rights reserved.
Publisher Subscriber
Backpressure
Error|Complete
Data Flow
35. © 2017 Pivotal Software, Inc. All rights reserved.
Back-pressure
•Allows to control the amount of inflight data
•Regulate the transfer between
•Slow publisher and fast consumer
•Fast publisher and slow consumer
https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-reactive-streams-and-java-8
36. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive Streams based libraries
37. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive Streams based libraries
RxJava
Reactor
Akka Streams
38. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive Streams based libraries
RxJava
Reactor
Akka Streams
39. © 2017 Pivotal Software, Inc. All rights reserved.
Reactor
•Natively built on top of Reactive Streams with Rx API
•Developed by Pivotal
•Focus on Java 8
•java.util.function.*
•Duration / CompletableFuture / Stream
• Lightweight Rx API with 2 types:
•Flux / Mono
https://projectreactor.io/
40. © 2017 Pivotal Software, Inc. All rights reserved.
Flux<T>
Mono<T>
41. © 2017 Pivotal Software, Inc. All rights reserved.
Flux<T> is a Publisher<T> for 0..n elements
42. © 2017 Pivotal Software, Inc. All rights reserved.
Flux<T>
Mono<T>
43. © 2017 Pivotal Software, Inc. All rights reserved.
Mono<T> is a Publisher<T> for 0..1 element
44. © 2017 Pivotal Software, Inc. All rights reserved.
Flux
Flux<Integer> stream1 = Flux.just(1, 2, 3)
.map(x -> x * 2)
.filter(x -> x > 2); // 4, 6
Flux<String> stream2 = Flux.just("a", "b", "c");
Flux.zip(stream1, stream2)
.doOneNext(t -> println(t.t1 + ":" + t.t2))
.subscribe();
Flux.merge(stream1, stream2)
.doOneNext(x -> println(x)).subscribe();
45. © 2017 Pivotal Software, Inc. All rights reserved.
Flux
Flux<Integer> stream1 = Flux.just(1, 2, 3)
.map(x -> x * 2)
.filter(x -> x > 2); // 4, 6
Flux<String> stream2 = Flux.just("a", "b", "c");
Flux.zip(stream1, stream2)
.doOneNext(t -> println(t.t1 + ":" + t.t2))
.subscribe();
Flux.merge(stream1, stream2)
.doOneNext(x -> println(x)).subscribe();
4:a
6:b
46. © 2017 Pivotal Software, Inc. All rights reserved.
Flux
Flux<Integer> stream1 = Flux.just(1, 2, 3)
.map(x -> x * 2)
.filter(x -> x > 2); // 4, 6
Flux<String> stream2 = Flux.just("a", "b", "c");
Flux.zip(stream1, stream2)
.doOneNext(t -> println(t.t1 + ":" + t.t2))
.subscribe();
Flux.merge(stream1, stream2)
.doOneNext(x -> println(x)).subscribe();
4:a
6:b
4
6
a
b
c
47. © 2017 Pivotal Software, Inc. All rights reserved.
String location = "Tokyo, Japan";
mainService.fetchWeather(location)
.timeout(Duration.ofSeconds(2))
.doOnError(ex -> logger.error(ex.getMessage()))
.onErrorResume(ex -> backupService.fetchWeather(location))
.map(w -> format("Weather in %s is %s", w.location(), w.description()))
.subscribe(message -> logger.info(message));
48. © 2017 Pivotal Software, Inc. All rights reserved.
String location = "Tokyo, Japan";
mainService.fetchWeather(location)
.timeout(Duration.ofSeconds(2))
.doOnError(ex -> logger.error(ex.getMessage()))
.onErrorResume(ex -> backupService.fetchWeather(location))
.map(w -> format("Weather in %s is %s", w.location(), w.description()))
.subscribe(message -> logger.info(message));
Mono<Weather> fetchWeather(String city);
49. © 2017 Pivotal Software, Inc. All rights reserved.
String location = "Tokyo, Japan";
mainService.fetchWeather(location)
.timeout(Duration.ofSeconds(2))
.doOnError(ex -> logger.error(ex.getMessage()))
.onErrorResume(ex -> backupService.fetchWeather(location))
.map(w -> format("Weather in %s is %s", w.location(), w.description()))
.subscribe(message -> logger.info(message));
times out and emits an error after 2 sec
50. © 2017 Pivotal Software, Inc. All rights reserved.
String location = "Tokyo, Japan";
mainService.fetchWeather(location)
.timeout(Duration.ofSeconds(2))
.doOnError(ex -> logger.error(ex.getMessage()))
.onErrorResume(ex -> backupService.fetchWeather(location))
.map(w -> format("Weather in %s is %s", w.location(), w.description()))
.subscribe(message -> logger.info(message));
logs a message in case of errors
51. © 2017 Pivotal Software, Inc. All rights reserved.
String location = "Tokyo, Japan";
mainService.fetchWeather(location)
.timeout(Duration.ofSeconds(2))
.doOnError(ex -> logger.error(ex.getMessage()))
.onErrorResume(ex -> backupService.fetchWeather(location))
.map(w -> format("Weather in %s is %s", w.location(), w.description()))
.subscribe(message -> logger.info(message));
switches to a different service in case of error
52. © 2017 Pivotal Software, Inc. All rights reserved.
String location = "Tokyo, Japan";
mainService.fetchWeather(location)
.timeout(Duration.ofSeconds(2))
.doOnError(ex -> logger.error(ex.getMessage()))
.onErrorResume(ex -> backupService.fetchWeather(location))
.map(w -> format("Weather in %s is %s", w.location(), w.description()))
.subscribe(message -> logger.info(message));
transforms a weather instance into a String message
53. © 2017 Pivotal Software, Inc. All rights reserved.
String location = "Tokyo, Japan";
mainService.fetchWeather(location)
.timeout(Duration.ofSeconds(2))
.doOnError(ex -> logger.error(ex.getMessage()))
.onErrorResume(ex -> backupService.fetchWeather(location))
.map(w -> format("Weather in %s is %s", w.location(), w.description()))
.subscribe(message -> logger.info(message));
triggers the processing of the chain
54. © 2017 Pivotal Software, Inc. All rights reserved.
Type comparison
No value Single value Multiple values
JDK CompletableFuture<Void> CompletableFuture<T> CompletableFuture<List<T>>
Reactive
Streams
Publisher<Void> Publisher<T> Publisher<T>
RxJava1 Completable Single<T> Observable<T>
RxJava2 Completable
Maybe<T>
Single<T>
Maybe<T>
Flowable<T> (*)
Observable<T>
Reactor Mono<Void> (*) Mono<T> (*) Flux<T> (*)
(*) ... implements Publisher
55. © 2017 Pivotal Software, Inc. All rights reserved.
java.util.concurrent.Flow in JDK 9
Reactive Streams JDK 9
org.reactivestreams java.util.concurrent
Publisher Flow.Publisher
Subscriber Flow.Subscriber
Subscription Flow.Subscription
Processor Flow.Processor
56. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive Streams ↔ j.u.c.Flow
// Reactive Streams (Reactor)
Publisher<String> pub = Flux.just("hello");
// java.util.concurrent.Flow
Flow.Publisher<String> flow =
JdkFlowAdapter.publisherToFlowPublisher(pub);
// java.util.concurrent.Flow
Flow.Publisher<String> flow = /* ... */;
// Reactive Streams (Reactor)
Flux<String> pub =
JdkFlowAdapter.flowPublisherToFlux(flow);
58. © 2017 Pivotal Software, Inc. All rights reserved.
Spring Framework 5.0
•Performance improvements
•JDK 9 - HTTP/2
•Reactive Spring
•Functional APIs
•Kotlin Support
https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and-trends
59. © 2017 Pivotal Software, Inc. All rights reserved.
Spring Framework 5.0
•Performance improvements
•JDK 9 - HTTP/2
•Reactive Spring
•Functional APIs
•Kotlin Support
https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and-trends
61. © 2017 Pivotal Software, Inc. All rights reserved.
@Controller, @RequestMapping
Spring MVC
Servlet API
Servlet Container
62. © 2017 Pivotal Software, Inc. All rights reserved.
@Controller, @RequestMapping
Spring MVC
Servlet API
Servlet Container Servlet 3.1, Netty, Undertow
Spring WebFlux
HTTP / Reactive Streams
63. © 2017 Pivotal Software, Inc. All rights reserved.
@Controller, @RequestMapping
Spring MVC
Servlet API
Servlet Container
Router functions
Servlet 3.1, Netty, Undertow
Spring WebFlux
HTTP / Reactive Streams
65. © 2017 Pivotal Software, Inc. All rights reserved.
Spring WebFlux
@RestController
public class HelloController {
@GetMapping
Flux<String> hello() {
return Flux.just("Hello", "World");
}
}
66. © 2017 Pivotal Software, Inc. All rights reserved.
Spring WebFlux
@RestController
public class EchoController {
@PostMapping("/echo")
Flux<String> upperCase
(@RequestBody Flux<String> body) {
return body.map(String::toUpperCase);
}
}
67. © 2017 Pivotal Software, Inc. All rights reserved.
Returns Infinite-Stream
@RestController
public class HelloController {
@GetMapping
Flux<Integer> infinite() {
Stream<Integer> s =
Stream.iterate(0, i -> i + 1);
return Flux.fromStream(s);
}}
68. © 2017 Pivotal Software, Inc. All rights reserved.
Returns Infinite-Stream
@RestController
public class TweetController {
@GetMapping
Flux<Tweet> infiniteTweet() {
Stream<Tweet> s =
Stream.iterate(0, i -> i + 1)
.map(i -> new Tweet("hello" + i));
return Flux.fromStream(s);}}
69. © 2017 Pivotal Software, Inc. All rights reserved.
Flux<Tweet> as a Server-Sent Events
curl ... -H "Accept: text/event-stream"
< HTTP/1.1 200 OK
< Content-Type: text/event-stream
<
data: {"text":"hello0"}
data: {"text":"hello1"}
data: {"text":"hello2"}
data: {"text":"hello3"}
...
70. © 2017 Pivotal Software, Inc. All rights reserved.
Flux<Tweet> as a JSON Stream
curl ... -H "Accept: application/stream+json"
< HTTP/1.1 200 OK
< Content-Type: application/stream+json
<
{"text":"hello0"}
{"text":"hello1"}
{"text":"hello2"}
{"text":"hello3"}
...
71. © 2017 Pivotal Software, Inc. All rights reserved.
WebClient
•Reactive HTTP Client
72. © 2017 Pivotal Software, Inc. All rights reserved.
WebClient
•Reactive HTTP Client
a nice RestTemplate alternative
73. © 2017 Pivotal Software, Inc. All rights reserved.
WebClient
•Reactive HTTP Client
WebClient webClient = WebClient.create();
Mono<String> s = webClient.get()
.uri("http://api.example.com")
.exchange()
.flatMap(res ->
res.bodyToMono(String.class));
a nice RestTemplate alternative
74. © 2017 Pivotal Software, Inc. All rights reserved.
WebClient
•Reactive HTTP Client
WebClient webClient = WebClient.create();
Mono<String> s = webClient.get()
.uri("http://api.example.com")
.retrieve()
.bodyToMono(String.class);
75. © 2017 Pivotal Software, Inc. All rights reserved.
WebClient
•Reactive HTTP Client
WebClient webClient = WebClient.create();
Flux<Tweet> tweets = webClient.get()
.uri("http://api.example.com")
.retrieve()
.bodyToFlux(Tweet.class);
76. © 2017 Pivotal Software, Inc. All rights reserved.
Flux<Tweet> WebClient
Streaming API
77. © 2017 Pivotal Software, Inc. All rights reserved.
Flux<Tweet>
✔ Reactive API
✔ Can consume (infinite) streams
WebClient
Streaming API
78. © 2017 Pivotal Software, Inc. All rights reserved.
Flux.zip(tweets, issues)
WebClient
Streaming API
REST API
WebClient
79. © 2017 Pivotal Software, Inc. All rights reserved.
Flux.zip(tweets, issues)
✔ Chain and compose
WebClient
Streaming API
REST API
WebClient
80. © 2017 Pivotal Software, Inc. All rights reserved.
WebClient
Web handler
WebFlux
81. © 2017 Pivotal Software, Inc. All rights reserved.
WebClient
Web handler
WebFlux
82. © 2017 Pivotal Software, Inc. All rights reserved.
WebClient
Web handler
WebFlux
✔ Shared resources (event loop, buffers)
✔ Built-in mocking capabilities
83. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
84. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
RouterFunctions<ServerResponse> routes() {
return RouterFunctions.route(
RequestPredicates.GET("/"),
req -> ServerResponse.ok()
.body(Mono.just("Hello","World"),
String.class));
}
85. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
RouterFunctions<ServerResponse> routes() {
return RouterFunctions.route(
RequestPredicates.GET("/"),
req -> ServerResponse.ok()
.body(Mono.just("Hello","World"),
String.class));
}
86. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
RouterFunctions<ServerResponse> routes() {
return route(
RequestPredicates.GET("/"),
req -> ServerResponse.ok()
.body(Mono.just("Hello","World"),
String.class));
}
87. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
RouterFunctions<ServerResponse> routes() {
return route(
RequestPredicates.GET("/"),
req -> ServerResponse.ok()
.body(Mono.just("Hello","World"),
String.class));
}
88. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
RouterFunctions<ServerResponse> routes() {
return route(GET("/"),
req -> ServerResponse.ok()
.body(Mono.just("Hello","World"),
String.class));
}
89. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
RouterFunctions<ServerResponse> routes() {
return route(GET("/"),
req -> ServerResponse.ok()
.body(Mono.just("Hello","World"),
String.class));
}
90. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
RouterFunctions<ServerResponse> routes() {
return route(GET("/"),
req -> ok()
.body(Mono.just("Hello","World"),
String.class));
}
91. © 2017 Pivotal Software, Inc. All rights reserved.
Router Functions
RouterFunctions<ServerResponse> routes() {
return route(POST("/echo"),
req -> {
Mono<String> body = req
.bodyToMono(String.class)
.map(String::toUpperCase);
return ok().body(body, String.class));
});}
92. © 2017 Pivotal Software, Inc. All rights reserved.
Spring Boot 2.0
Spring Boot 2.0 supports
Spring 5 and WebFlux ✨
93. © 2017 Pivotal Software, Inc. All rights reserved.
start.spring.io
95. © 2017 Pivotal Software, Inc. All rights reserved.
Spring MVC VS Spring WebFlux
@GetMapping
Flux<String> hello() {
return Flux.just("Hello")
.delayElements(
ofSeconds(1));
}
@GetMapping
String hello() {
Thread.sleep(1000);
return"Hello";
}
server.tomcat.max-threads=200 (default)
https://gist.github.com/making/f32e81c5684a5fd810039854091dd793
Tomcat Netty
96. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 100
97. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 100
Transaction rate: 94.79 trans/sec
Response time: 1.05 sec
Live peek threads: 129
98. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 100
Transaction rate: 94.79 trans/sec
Response time: 1.05 sec
Live peek threads: 129
Transaction rate: 94.88 trans/sec
Response time: 1.05 sec
Live peek threads: 30
99. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 200
100. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 200
Transaction rate: 182.65 trans/sec
Response time: 1.07 sec
Live peek threads: 218
101. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 200
Transaction rate: 182.65 trans/sec
Response time: 1.07 sec
Live peek threads: 218
Transaction rate: 184.50 trans/sec
Response time: 1.06 sec
Live peek threads: 30
102. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 300
103. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 300
Transaction rate: 192.31 trans/sec
Response time: 1.51 sec
Live peek threads: 218
104. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 300
Transaction rate: 192.31 trans/sec
Response time: 1.51 sec
Live peek threads: 218
Transaction rate: 278.55 trans/sec
Response time: 1.04 sec
Live peek threads: 30
105. © 2017 Pivotal Software, Inc. All rights reserved.
Blocking in WebFlux??
@GetMapping
Flux<String> hello() {
Thread.sleep(1000); // blocking!
return Flux.just("Hello");
}
106. © 2017 Pivotal Software, Inc. All rights reserved.
Concurrent users = 100
Transaction rate: 7.94 trans/sec
Response time: 12 sec
Live peek threads: 22 😱
108. © 2017 Pivotal Software, Inc. All rights reserved.
End-to-End Reactive
Controller
Repository
Service
Filter
Publisher Publisher Publisher Publisher
Publisher Publisher Publisher Publisher
109. © 2017 Pivotal Software, Inc. All rights reserved.
End-to-End Reactive
Controller
Repository
Service
Filter
Publisher Publisher Publisher Publisher
Publisher Publisher Publisher Publisher
110. © 2017 Pivotal Software, Inc. All rights reserved.
Spring Projects
Reactor Ecosystem
Spring Security
Spring Data
Spring Cloud
Spring Integration
Reactor Projects
Reactor Netty
Reactor Kafka
Lettuce
Thymeleaf
111. © 2017 Pivotal Software, Inc. All rights reserved.
Spring Projects
Reactor Ecosystem
Spring Security
Spring Data
Spring Cloud
Spring Integration
Reactor Projects
Reactor Netty
Reactor Kafka
Lettuce
MongoDB Redis Cassandra Couchbase
Thymeleaf
112. © 2017 Pivotal Software, Inc. All rights reserved.
Spring Data Release Train Kay
•Supports
•Reactive Template
•Reactive Repository
113. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive Repository
public interface ReactiveCrudRepository<ID,T> {
Mono<T> findById(ID id);
Mono<T> findById(Mono<ID> id);
Flux<T> findAll();
Mono<Long> count();
Mono<T> save(T entity);
Mono<T> saveAll(Publisher<T> entityStream);
Mono<Void> delete(T entity)
// ...
}
114. © 2017 Pivotal Software, Inc. All rights reserved.
@Tailable for Infinite streams
public interface PersonRepository
extends ReactiveMongoRepository<Person,String> {
@Tailable
Flux<Person> findByFirstname(String firstname);
}
115. © 2017 Pivotal Software, Inc. All rights reserved.
What about JPA/JDBC?
🤔
116. © 2017 Pivotal Software, Inc. All rights reserved.
What about JPA/JDBC?
•JDBC is blocking ⌛
•JPA is blocking ⌛
🤔
117. © 2017 Pivotal Software, Inc. All rights reserved.
What about JPA/JDBC?
•JDBC is blocking ⌛
•JPA is blocking ⌛
🤔
https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/
CONF1578%2020160916.pdf
https://www.voxxed.com/blog/2016/09/non-blocking-database-access/
•Non-Blocking JDBC in JDK 10?
118. © 2017 Pivotal Software, Inc. All rights reserved.
Switching execution context
BlockingRepository<User> repo = ...;
Flux<User> users =
Flux.defer(() ->
Flux.fromIterable(repo.findAll()))
.subscribeOn(Schedulers.elastic());
Make the subscription and request happen
on a particular thread
119. © 2017 Pivotal Software, Inc. All rights reserved.
Switching execution context
Flux<User> users = ...;
BlockingRepository<User> repo = ...;
users.publishOn(Schedulers.elastic())
.doOneNext(u -> repo.save(u))
.then() ;
Switch rest of the flux on a particular thread
120. ‹#›© 2016 Pivotal Software, Inc. All rights reserved.
Reactive Web Applications
Example
121. © 2017 Pivotal Software, Inc. All rights reserved.
💻
💻
💻
Server-Sent Events
POST
PUBLISH
SUBSCRIBE
INCR
Pub/Sub Application
bit.ly/jdtd1d5
122. © 2017 Pivotal Software, Inc. All rights reserved.
API Gateway
• Rate Limiter
• Web Application Firewall
123. © 2017 Pivotal Software, Inc. All rights reserved.
API Gateway
• Rate Limiter
• Web Application Firewall
✅ Spring Cloud Gateway
124. © 2017 Pivotal Software, Inc. All rights reserved.
Route Services in Cloud Foundry
125. © 2017 Pivotal Software, Inc. All rights reserved.
FFB (Frontend for Backend)
💻
📱
Frontend Backend
126. © 2017 Pivotal Software, Inc. All rights reserved.
Reactive Everywhere
CF Java Client
Firehose Nozzle
Firehose Nozzle
Cloud Foundry
💻
Firehose
Doppler Endpoint
WebSocket
Rector Kafka
(Publisher)
Rector Kafka
(Consumer)
Reactor Netty
Sever-Sent Event
Spring WebFluxLog, Metrics
127. © 2017 Pivotal Software, Inc. All rights reserved.
Spring WebFlux
• https://blog.ik.am/entries/417
• https://blog.ik.am/entries/418
• ...
128. © 2017 Pivotal Software, Inc. All rights reserved.
Thank you!!
• Handson
• https://github.com/reactor/lite-rx-api-hands-on
• Slides
• https://speakerdeck.com/simonbasle/reactor-3
• https://speakerdeck.com/sdeleuze/developing-reactive-applications-with-
reactive-streams-and-java-8
• https://speakerdeck.com/snicoll/spring-framework-5-dot-0-themes-and-
trends
• https://speakerdeck.com/mp911de/reactive-spring
• https://speakerdeck.com/christophstrobl/sneak-peek-on-spring-data-kay
• https://speakerdeck.com/normanmaurer/netty-meetup-2017-san-francisco