Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Spring WebFluxで学ぶReactive Application / Introduction to Reactive

Ryo Shindo
August 08, 2018
2.2k

Spring WebFluxで学ぶReactive Application / Introduction to Reactive

2018/08/02 Thu 社内勉強会用資料
公開用に何枚かスライド削ってます。

Ryo Shindo

August 08, 2018
Tweet

Transcript

  1. Copyright © Acroquest Technology Co., Ltd. All rights reserved. 1

    Spring WebFluxで学ぶ Reactive Application Acroquest Technology株式会社 進藤 遼
  2. 自己紹介 • 進藤 遼 @shindo_ryo • Acroquest Technology株式会社 • (元)文系のJavaエンジニア

    • ロックマンXのシグマが倒せない Copyright © Acroquest Technology Co., Ltd. All rights reserved. 2
  3. 目次 1. Reactive とは 2. 背景 3. Spring WebFlux 4.

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

    © Acroquest Technology Co., Ltd. All rights reserved. 4
  5. Copyright © Acroquest Technology Co., Ltd. All rights reserved. 5

    命令型プログラミング Reactiveプログラミング
  6. 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の値が変わることはない
  7. Reactive とは • Reactiveプログラミング • データを生成するPublisherと データを受信して処理するConsumer (Subscriber) との関係を記述する Copyright

    © Acroquest Technology Co., Ltd. All rights reserved. 10 Publisher Consumer (Subscriber) observe notify 要するにObserverパターンを強力にしたような感じ(雑) このEvent-DrivenなプログラミングモデルとNon-Blocking との相性が良い
  8. 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 はレスポンスが終わるまで 次のリクエストを処理しない
  9. 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
  10. Reactive とは 1. Non-Blocking API Copyright © Acroquest Technology Co.,

    Ltd. All rights reserved. 14 Event Loop スレッドをブロックしない イベント(※)に対応したコールバックを 順々に処理していく ※サーバサイドだともっぱら イベント = (Network) I/O
  11. Reactive とは 1. Reactiveのここがすごい! ① 少ないスレッドで多くのリクエストを処理できる (=> 安定したスループット) ② I/O

    Wait の多い処理でもスレッドを専有しない 2. Reactiveのここがダメ! ① 設計・実装が難しい ② テストが難しい ③ レスポンスタイム重視の場合はBlocking (ex: Servlet) のほうが有利な場合も Copyright © Acroquest Technology Co., Ltd. All rights reserved. 15
  12. 背景 1. マイクロサービス間でのネットワーク通信の増大 Copyright © Acroquest Technology Co., Ltd. All

    rights reserved. 19 Service A Service B Service C Service B がスローダウンすると・・・
  13. 背景 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のスレッドを専有してしまう =障害の伝播
  14. 背景 2. 低速なネットワークとの通信の増加 Copyright © Acroquest Technology Co., Ltd. All

    rights reserved. 21 モバイルなどの比較的低速なネットワークから 大量のリクエストを受け取る必要
  15. 背景 3. 大量のトラフィックへの対応 Copyright © Acroquest Technology Co., Ltd. All

    rights reserved. 22 大量のトラフィックをさばくために スレッドを増やす = スケールアウトで対応 =>お金がかかる!! ・・・・・・・・・ ・・・
  16. Spring WebFlux • Springのエコシステムの上でReactive Application を開発するためのWebフレームワーク • @Controllerや@RequestMappingなどの、 WebMVCでおなじみのアノテーションを使う ことができる

    • コアライブラリにReactor (by Pivotal) を採用 ※RxJavaもサポート • ランタイムはNetty, Tomcatなどから選ぶ Copyright © Acroquest Technology Co., Ltd. All rights reserved. 25
  17. Spring WebFlux • pom.xml Copyright © Acroquest Technology Co., Ltd.

    All rights reserved. 26 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> Bootでは spring-boot-starter-webflux を追加するだけ
  18. Spring WebFlux Copyright © Acroquest Technology Co., Ltd. All rights

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

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

    reserved. 29 Mono<T> • 0 .. 1 個のデータを発行 • ストリーミング感ないけど、結構これだけで頑張れる Flux<T> • 0 .. n 個のデータを発行 • List に似ているが List ではない • List に変換しようとしてよくブロックする
  21. 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
  22. Spring WebFlux • Pub/Subモデル(再掲) Copyright © Acroquest Technology Co., Ltd.

    All rights reserved. 31 Publisher Consumer (Subscriber) observe notify
  23. 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 ※色々省略しているので正確でないです
  24. 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
  25. Spring WebFlux • Controller Copyright © Acroquest Technology Co., Ltd.

    All rights reserved. 34 @RestController public class EchoController { @PostMapping(path = "/hello") Flux<String> hello(@RequestBody Flux<String> 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を返す
  26. Spring WebFlux • Stream Copyright © Acroquest Technology Co., Ltd.

    All rights reserved. 35 @GetMapping(path = "/stream") Flux<Map<String, LocalDateTime>> 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"}] ストリームになっていない?
  27. 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"}
  28. 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<String> hello(@RequestBody Flux<String> request) { return request.map(name -> "Hello, " + name + "!").subscribe(); } } ※Controllerの中でsubscribe してはいけない FW側でsubscribe してレスポンスを返却している。
  29. 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<String> hello(@RequestBody Flux<String> request) { Thread.sleep(1000L); return request.map(name -> "Hello, " + name + "!"); } } ※Blocking 禁止!! スレッド数が少ないため、ブロックすると全体の性能が極端 に低下する Flux#delaySubscription(Duration) などを利用する
  30. WebClient • ReactiveなHTTP Client ➢ Non-BlockingかつReactiveなHTTP通信 ➢ ラムダ式を使ったFluent API ➢

    Mono/Fluxを戻り値に返す • RestTemplateの代替 ➢ WebClient単体で利用可能 ➢ 同期的な呼び出しも可能 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 39
  31. 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リクエストは実行されない
  32. Reactive クライアント 1. Reactive MongoDB 2. Reactive Redis 3. Reactive

    Cassandra 4. Reactor Kafka Copyright © Acroquest Technology Co., Ltd. All rights reserved. 41
  33. 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
  34. Copyright © Acroquest Technology Co., Ltd. All rights reserved. 43

    https://www.slideshare.net/ArisaSasaki/jsug-20185-spring-io-108053900
  35. Spring MVC or WebFlux? • 高スループットを出すならWebFlux • 実装しやすさはWebMVC • プログラミングモデルが異なるため、

    WebMVC -> WebFlux の書き換えは死ぬ(確信) • 現時点ではまだ “基本WebMVC” という選択になるが、 そのうち “基本WebFlux” になるかも Copyright © Acroquest Technology Co., Ltd. All rights reserved. 44
  36. Use Cases 1. N + 1 問題 Q:次の処理のレスポンスタイムは? Copyright ©

    Acroquest Technology Co., Ltd. All rights reserved. 46 商品サービス 在庫サービス Flux<Item> Mono<Stock> 5件の商品 リストを返す パラメータの商品IDを見て その商品の在庫数を返す ※ただし処理に1秒かかる
  37. Use Cases 1. N + 1 問題 正解: Copyright ©

    Acroquest Technology Co., Ltd. All rights reserved. 47 1.232s リクエストが並列で動いている
  38. まとめ 1. Blocking = 2. Reactive でスループット↑↑ 3. RDBへのアクセスは現時点では 4.

    正直難しいので勉強しよう Copyright © Acroquest Technology Co., Ltd. All rights reserved. 48
  39. Copyright © Acroquest Technology Co., Ltd. All rights reserved. 49

    ご清聴ありがとうございました。 Infrastructures Evolution