Slide 1

Slide 1 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 1 Spring WebFluxで学ぶ Reactive Application Acroquest Technology株式会社 進藤 遼

Slide 2

Slide 2 text

自己紹介 • 進藤 遼 @shindo_ryo • Acroquest Technology株式会社 • (元)文系のJavaエンジニア • ロックマンXのシグマが倒せない Copyright © Acroquest Technology Co., Ltd. All rights reserved. 2

Slide 3

Slide 3 text

目次 1. Reactive とは 2. 背景 3. Spring WebFlux 4. Use Cases Copyright © Acroquest Technology Co., Ltd. All rights reserved. 3

Slide 4

Slide 4 text

Reactive とは • Non-Blocking • Event-Driven • Functional Programming Copyright © Acroquest Technology Co., Ltd. All rights reserved. 4

Slide 5

Slide 5 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 5 命令型プログラミング Reactiveプログラミング

Slide 6

Slide 6 text

Reactive とは • 命令型プログラミング • 計算の「手続き」を記述する Copyright © Acroquest Technology Co., Ltd. All rights reserved. 6 int a = 3; int b = 4; int c = a * b; // 12 a = 5; 上から順番に計算されて、 後からaの値が変わっても cの値が変わることはない

Slide 7

Slide 7 text

Reactive とは • Reactiveプログラミング • データフローに着目したEvent-Drivenなプログラミング Copyright © Acroquest Technology Co., Ltd. All rights reserved. 7 3 4 12 a b a * b

Slide 8

Slide 8 text

Reactive とは • Reactiveプログラミング • データフローに着目したEvent-Drivenなプログラミング Copyright © Acroquest Technology Co., Ltd. All rights reserved. 8 5 4 12 a b a * b

Slide 9

Slide 9 text

Reactive とは • Reactiveプログラミング • データフローに着目したEvent-Drivenなプログラミング Copyright © Acroquest Technology Co., Ltd. All rights reserved. 9 5 4 20 a b a * b

Slide 10

Slide 10 text

Reactive とは • Reactiveプログラミング • データを生成するPublisherと データを受信して処理するConsumer (Subscriber) との関係を記述する Copyright © Acroquest Technology Co., Ltd. All rights reserved. 10 Publisher Consumer (Subscriber) observe notify 要するにObserverパターンを強力にしたような感じ(雑) このEvent-DrivenなプログラミングモデルとNon-Blocking との相性が良い

Slide 11

Slide 11 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 11 Blocking API Non-Blocking API

Slide 12

Slide 12 text

Reactive とは • Blocking API Copyright © Acroquest Technology Co., Ltd. All rights reserved. 12 Thread 1 Thread 2 Thread 3 Request A Request E Request B Request C Request D Request F Thread はレスポンスが終わるまで 次のリクエストを処理しない

Slide 13

Slide 13 text

Reactive とは • Blocking API Copyright © Acroquest Technology Co., Ltd. All rights reserved. 13 APP DB Network I/O JDBC I/O待ちの間、スレッドは何もしていない! I/O Wait I/O Wait

Slide 14

Slide 14 text

Reactive とは 1. Non-Blocking API Copyright © Acroquest Technology Co., Ltd. All rights reserved. 14 Event Loop スレッドをブロックしない イベント(※)に対応したコールバックを 順々に処理していく ※サーバサイドだともっぱら イベント = (Network) I/O

Slide 15

Slide 15 text

Reactive とは 1. Reactiveのここがすごい! ① 少ないスレッドで多くのリクエストを処理できる (=> 安定したスループット) ② I/O Wait の多い処理でもスレッドを専有しない 2. Reactiveのここがダメ! ① 設計・実装が難しい ② テストが難しい ③ レスポンスタイム重視の場合はBlocking (ex: Servlet) のほうが有利な場合も Copyright © Acroquest Technology Co., Ltd. All rights reserved. 15

Slide 16

Slide 16 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 16 なぜ Reactive が重要なのか?

Slide 17

Slide 17 text

背景 1. マイクロサービス間でのネットワーク通信の増大 2. 低速なネットワークとの通信の増加 3. 大量のトラフィックへの対応 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 17

Slide 18

Slide 18 text

背景 1. マイクロサービス間でのネットワーク通信の増大 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 18 Service A Service B Service C

Slide 19

Slide 19 text

背景 1. マイクロサービス間でのネットワーク通信の増大 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 19 Service A Service B Service C Service B がスローダウンすると・・・

Slide 20

Slide 20 text

背景 1. マイクロサービス間でのネットワーク通信の増大 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 20 Service A Service B Service C Service A -> Service B の呼び出しのI/O Wait が増えてService Aのスレッドを専有してしまう =障害の伝播

Slide 21

Slide 21 text

背景 2. 低速なネットワークとの通信の増加 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 21 モバイルなどの比較的低速なネットワークから 大量のリクエストを受け取る必要

Slide 22

Slide 22 text

背景 3. 大量のトラフィックへの対応 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 22 大量のトラフィックをさばくために スレッドを増やす = スケールアウトで対応 =>お金がかかる!! ・・・・・・・・・ ・・・

Slide 23

Slide 23 text

背景 • Non-Blocking にすれば少ないスレッドで 多くのリクエストをさばける • 必要なスレッドが少なくなればサーバー台数が減る • サーバ台数が減ればコストが減る Copyright © Acroquest Technology Co., Ltd. All rights reserved. 23 Blocking =

Slide 24

Slide 24 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 24 Spring WebFlux とは?

Slide 25

Slide 25 text

Spring WebFlux • Springのエコシステムの上でReactive Application を開発するためのWebフレームワーク • @Controllerや@RequestMappingなどの、 WebMVCでおなじみのアノテーションを使う ことができる • コアライブラリにReactor (by Pivotal) を採用 ※RxJavaもサポート • ランタイムはNetty, Tomcatなどから選ぶ Copyright © Acroquest Technology Co., Ltd. All rights reserved. 25

Slide 26

Slide 26 text

Spring WebFlux • pom.xml Copyright © Acroquest Technology Co., Ltd. All rights reserved. 26 org.springframework.boot spring-boot-starter-webflux Bootでは spring-boot-starter-webflux を追加するだけ

Slide 27

Slide 27 text

Spring WebFlux Copyright © Acroquest Technology Co., Ltd. All rights reserved. 27 WebMVCと同じく@Controller, @RequestMappingを使える ランタイムは基本的にNetty (Tomcatを使うとServletの非同期APIを利用)

Slide 28

Slide 28 text

Spring WebFlux Copyright © Acroquest Technology Co., Ltd. All rights reserved. 28 Publisher Mono Flux 0 .. 1 個の要素を Publishする 0 .. n 個の要素を Publishする

Slide 29

Slide 29 text

Spring WebFlux Copyright © Acroquest Technology Co., Ltd. All rights reserved. 29 Mono • 0 .. 1 個のデータを発行 • ストリーミング感ないけど、結構これだけで頑張れる Flux • 0 .. n 個のデータを発行 • List に似ているが List ではない • List に変換しようとしてよくブロックする

Slide 30

Slide 30 text

Spring WebFlux • コールバックスタイルで処理をつないでいく Copyright © Acroquest Technology Co., Ltd. All rights reserved. 30 Flux.interval(Duration.ofSeconds(1)) .publishOn(Schedulers.parallel()) .log() .zipWith(Flux.just(“Taro", “Jiro", “Saburo"), (f1, f2) -> f2) .map(String::toUpperCase) .subscribe(name -> System.out.println(name)); 1秒間隔 データの生成 最後にsubscribe

Slide 31

Slide 31 text

Spring WebFlux • Pub/Subモデル(再掲) Copyright © Acroquest Technology Co., Ltd. All rights reserved. 31 Publisher Consumer (Subscriber) observe notify

Slide 32

Slide 32 text

Spring WebFlux • 実行モデル Copyright © Acroquest Technology Co., Ltd. All rights reserved. 32 Flux.just(“one”, “two”, “three”) .map(String::toUpperCase) .subscribe(System.out::println); Publisher Subscriber / Subscription Subscriber subscribe subscribe onNext onNext ※色々省略しているので正確でないです

Slide 33

Slide 33 text

Spring WebFlux • 各処理は同じスレッドとは限らない Copyright © Acroquest Technology Co., Ltd. All rights reserved. 33 Mono.fromCallable(() -> LocalDateTime.now()) .repeat(6) .parallel(5) .runOn(Schedulers.parallel()) .subscribe( dateTime -> System.out.printf("[%s] time -> %s%n", Thread.currentThread().getName(), dateTime)); [parallel-2] time -> 2018-07-29T19:32:52.850318900 [parallel-3] time -> 2018-07-29T19:32:52.850318900 [parallel-1] time -> 2018-07-29T19:32:52.849319700 [parallel-4] time -> 2018-07-29T19:32:52.850318900 [parallel-1] time -> 2018-07-29T19:32:52.850318900 [parallel-1] time -> 2018-07-29T19:32:52.850318900

Slide 34

Slide 34 text

Spring WebFlux • Controller Copyright © Acroquest Technology Co., Ltd. All rights reserved. 34 @RestController public class EchoController { @PostMapping(path = "/hello") Flux hello(@RequestBody Flux request) { return request.map(name -> "Hello, " + name + "!"); } } $ curl -XPOST -H "Content-Type: text/plain" localhost:8080/hello -d "shindo" Hello, shindo! Flux/Mono を受け取り Flux/Monoを返す

Slide 35

Slide 35 text

Spring WebFlux • Stream Copyright © Acroquest Technology Co., Ltd. All rights reserved. 35 @GetMapping(path = "/stream") Flux> stream() { return Flux.range(1, 5) .map(i -> Map.of("data", LocalDateTime.now())) .delayElements(Duration.ofMillis(500L)); } $ curl -v -XGET localhost:8080/stream [{"data":"2018-07-30T01:00:10.6239329"},{"data":"2018-07- 30T01:00:10.6259333"},{"data":"2018-07- 30T01:00:10.6259333"},{"data":"2018-07- 30T01:00:10.6259333"},{"data":"2018-07-30T01:00:10.6259333"}] ストリームになっていない?

Slide 36

Slide 36 text

Spring WebFlux • Content Negotiation Copyright © Acroquest Technology Co., Ltd. All rights reserved. 36 $ curl -XGET -H "Accept: application/stream+json" localhost:8080/stream {"data":"2018-07-30T01:00:36.3017757"} {"data":"2018-07-30T01:00:36.3017757"} {"data":"2018-07-30T01:00:36.3017757"} {"data":"2018-07-30T01:00:36.3017757"} {"data":"2018-07-30T01:00:36.3017757"} $ curl -XGET -H "Accept: text/event-stream" localhost:8080/stream data:{"data":"2018-07-30T01:01:09.2095158"} data:{"data":"2018-07-30T01:01:09.2095158"} data:{"data":"2018-07-30T01:01:09.2095158"} data:{"data":"2018-07-30T01:01:09.2095158"} data:{"data":"2018-07-30T01:01:09.2095158"}

Slide 37

Slide 37 text

Spring WebFlux • ダメな例① Copyright © Acroquest Technology Co., Ltd. All rights reserved. 37 @RestController public class EchoController { @PostMapping(path = "/hello", consumes = MediaType.TEXT_PLAIN_VALUE, produces = MediaType.TEXT_PLAIN_VALUE) Flux hello(@RequestBody Flux request) { return request.map(name -> "Hello, " + name + "!").subscribe(); } } ※Controllerの中でsubscribe してはいけない FW側でsubscribe してレスポンスを返却している。

Slide 38

Slide 38 text

Spring WebFlux • ダメな例② Copyright © Acroquest Technology Co., Ltd. All rights reserved. 38 @RestController public class EchoController { @PostMapping(path = "/hello", consumes = MediaType.TEXT_PLAIN_VALUE, produces = MediaType.TEXT_PLAIN_VALUE) Flux hello(@RequestBody Flux request) { Thread.sleep(1000L); return request.map(name -> "Hello, " + name + "!"); } } ※Blocking 禁止!! スレッド数が少ないため、ブロックすると全体の性能が極端 に低下する Flux#delaySubscription(Duration) などを利用する

Slide 39

Slide 39 text

WebClient • ReactiveなHTTP Client ➢ Non-BlockingかつReactiveなHTTP通信 ➢ ラムダ式を使ったFluent API ➢ Mono/Fluxを戻り値に返す • RestTemplateの代替 ➢ WebClient単体で利用可能 ➢ 同期的な呼び出しも可能 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 39

Slide 40

Slide 40 text

WebClient • Example Copyright © Acroquest Technology Co., Ltd. All rights reserved. 40 WebClient webClient = WebClient.create("https://api.github.com"); String name = webClient.get() .uri("/users/{username}", "rshindo") .retrieve() .bodyToMono(JsonNode.class) .map(resp -> resp.findValue("name").asText()) .block(); System.out.println("name = " + name); block / subscribe されるまでは HTTPリクエストは実行されない

Slide 41

Slide 41 text

Reactive クライアント 1. Reactive MongoDB 2. Reactive Redis 3. Reactive Cassandra 4. Reactor Kafka Copyright © Acroquest Technology Co., Ltd. All rights reserved. 41

Slide 42

Slide 42 text

RDBへのアクセス? • ノンブロッキングAPIはサポートされていない • スレッドプールを別に用意して 非同期呼び出しをしているケースが多い (Play2など) • JDBC Next: A New Asynchronous API for Connecting to a Database https://www.slideshare.net/ypoirier/jdbc-next- a-new-asynchronous-api-for-connecting-to-a- database Copyright © Acroquest Technology Co., Ltd. All rights reserved. 42

Slide 43

Slide 43 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 43 https://www.slideshare.net/ArisaSasaki/jsug-20185-spring-io-108053900

Slide 44

Slide 44 text

Spring MVC or WebFlux? • 高スループットを出すならWebFlux • 実装しやすさはWebMVC • プログラミングモデルが異なるため、 WebMVC -> WebFlux の書き換えは死ぬ(確信) • 現時点ではまだ “基本WebMVC” という選択になるが、 そのうち “基本WebFlux” になるかも Copyright © Acroquest Technology Co., Ltd. All rights reserved. 44

Slide 45

Slide 45 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 45 Use Cases

Slide 46

Slide 46 text

Use Cases 1. N + 1 問題 Q:次の処理のレスポンスタイムは? Copyright © Acroquest Technology Co., Ltd. All rights reserved. 46 商品サービス 在庫サービス Flux Mono 5件の商品 リストを返す パラメータの商品IDを見て その商品の在庫数を返す ※ただし処理に1秒かかる

Slide 47

Slide 47 text

Use Cases 1. N + 1 問題 正解: Copyright © Acroquest Technology Co., Ltd. All rights reserved. 47 1.232s リクエストが並列で動いている

Slide 48

Slide 48 text

まとめ 1. Blocking = 2. Reactive でスループット↑↑ 3. RDBへのアクセスは現時点では 4. 正直難しいので勉強しよう Copyright © Acroquest Technology Co., Ltd. All rights reserved. 48

Slide 49

Slide 49 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 49 ご清聴ありがとうございました。 Infrastructures Evolution