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.1k

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株式会社
    進藤 遼

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  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の値が変わることはない

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  12. 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 はレスポンスが終わるまで
    次のリクエストを処理しない

    View full-size slide

  13. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  20. 背景
    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のスレッドを専有してしまう
    =障害の伝播

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  26. 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
    を追加するだけ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  30. 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

    View full-size slide

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

    View full-size slide

  32. 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
    ※色々省略しているので正確でないです

    View full-size slide

  33. 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

    View full-size slide

  34. 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を返す

    View full-size slide

  35. 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"}]
    ストリームになっていない?

    View full-size slide

  36. 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"}

    View full-size slide

  37. 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 してレスポンスを返却している。

    View full-size slide

  38. 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) などを利用する

    View full-size slide

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

    View full-size slide

  40. 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リクエストは実行されない

    View full-size slide

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

    View full-size slide

  42. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide