2018/08/02 Thu 社内勉強会用資料 公開用に何枚かスライド削ってます。
Copyright © Acroquest Technology Co., Ltd. All rights reserved. 1Spring WebFluxで学ぶReactive ApplicationAcroquest Technology株式会社進藤 遼
View Slide
自己紹介• 進藤 遼 @shindo_ryo• Acroquest Technology株式会社• (元)文系のJavaエンジニア• ロックマンXのシグマが倒せないCopyright © Acroquest Technology Co., Ltd. All rights reserved. 2
目次1. Reactive とは2. 背景3. Spring WebFlux4. Use CasesCopyright © Acroquest Technology Co., Ltd. All rights reserved. 3
Reactive とは• Non-Blocking• Event-Driven• Functional ProgrammingCopyright © Acroquest Technology Co., Ltd. All rights reserved. 4
Copyright © Acroquest Technology Co., Ltd. All rights reserved. 5命令型プログラミングReactiveプログラミング
Reactive とは• 命令型プログラミング• 計算の「手続き」を記述するCopyright © Acroquest Technology Co., Ltd. All rights reserved. 6int a = 3;int b = 4;int c = a * b; // 12a = 5;上から順番に計算されて、後からaの値が変わってもcの値が変わることはない
Reactive とは• Reactiveプログラミング• データフローに着目したEvent-DrivenなプログラミングCopyright © Acroquest Technology Co., Ltd. All rights reserved. 73412aba * b
Reactive とは• Reactiveプログラミング• データフローに着目したEvent-DrivenなプログラミングCopyright © Acroquest Technology Co., Ltd. All rights reserved. 85412aba * b
Reactive とは• Reactiveプログラミング• データフローに着目したEvent-DrivenなプログラミングCopyright © Acroquest Technology Co., Ltd. All rights reserved. 95420aba * b
Reactive とは• Reactiveプログラミング• データを生成するPublisherとデータを受信して処理するConsumer (Subscriber)との関係を記述するCopyright © Acroquest Technology Co., Ltd. All rights reserved. 10PublisherConsumer(Subscriber)observenotify要するにObserverパターンを強力にしたような感じ(雑)このEvent-DrivenなプログラミングモデルとNon-Blockingとの相性が良い
Copyright © Acroquest Technology Co., Ltd. All rights reserved. 11Blocking APINon-Blocking API
Reactive とは• Blocking APICopyright © Acroquest Technology Co., Ltd. All rights reserved. 12Thread 1Thread 2Thread 3Request A Request ERequest BRequest CRequest DRequest FThread はレスポンスが終わるまで次のリクエストを処理しない
Reactive とは• Blocking APICopyright © Acroquest Technology Co., Ltd. All rights reserved. 13APP DBNetwork I/O JDBCI/O待ちの間、スレッドは何もしていない!I/O Wait I/O Wait
Reactive とは1. Non-Blocking APICopyright © Acroquest Technology Co., Ltd. All rights reserved. 14Event Loopスレッドをブロックしないイベント(※)に対応したコールバックを順々に処理していく※サーバサイドだともっぱらイベント = (Network) I/O
Reactive とは1. Reactiveのここがすごい!① 少ないスレッドで多くのリクエストを処理できる(=> 安定したスループット)② I/O Wait の多い処理でもスレッドを専有しない2. Reactiveのここがダメ!① 設計・実装が難しい② テストが難しい③ レスポンスタイム重視の場合はBlocking (ex: Servlet)のほうが有利な場合もCopyright © Acroquest Technology Co., Ltd. All rights reserved. 15
Copyright © Acroquest Technology Co., Ltd. All rights reserved. 16なぜ Reactive が重要なのか?
背景1. マイクロサービス間でのネットワーク通信の増大2. 低速なネットワークとの通信の増加3. 大量のトラフィックへの対応Copyright © Acroquest Technology Co., Ltd. All rights reserved. 17
背景1. マイクロサービス間でのネットワーク通信の増大Copyright © Acroquest Technology Co., Ltd. All rights reserved. 18Service AService BService C
背景1. マイクロサービス間でのネットワーク通信の増大Copyright © Acroquest Technology Co., Ltd. All rights reserved. 19Service AService BService CService B がスローダウンすると・・・
背景1. マイクロサービス間でのネットワーク通信の増大Copyright © Acroquest Technology Co., Ltd. All rights reserved. 20Service AService BService CService A -> Service B の呼び出しのI/O Waitが増えてService Aのスレッドを専有してしまう=障害の伝播
背景2. 低速なネットワークとの通信の増加Copyright © Acroquest Technology Co., Ltd. All rights reserved. 21モバイルなどの比較的低速なネットワークから大量のリクエストを受け取る必要
背景3. 大量のトラフィックへの対応Copyright © Acroquest Technology Co., Ltd. All rights reserved. 22大量のトラフィックをさばくためにスレッドを増やす = スケールアウトで対応=>お金がかかる!!・・・・・・・・・・・・
背景• Non-Blocking にすれば少ないスレッドで多くのリクエストをさばける• 必要なスレッドが少なくなればサーバー台数が減る• サーバ台数が減ればコストが減るCopyright © Acroquest Technology Co., Ltd. All rights reserved. 23Blocking =
Copyright © Acroquest Technology Co., Ltd. All rights reserved. 24Spring WebFlux とは?
Spring WebFlux• Springのエコシステムの上でReactive Applicationを開発するためのWebフレームワーク• @Controllerや@RequestMappingなどの、WebMVCでおなじみのアノテーションを使うことができる• コアライブラリにReactor (by Pivotal) を採用※RxJavaもサポート• ランタイムはNetty, Tomcatなどから選ぶCopyright © Acroquest Technology Co., Ltd. All rights reserved. 25
Spring WebFlux• pom.xmlCopyright © Acroquest Technology Co., Ltd. All rights reserved. 26org.springframework.bootspring-boot-starter-webfluxBootでは spring-boot-starter-webfluxを追加するだけ
Spring WebFluxCopyright © Acroquest Technology Co., Ltd. All rights reserved. 27WebMVCと同じく@Controller,@RequestMappingを使えるランタイムは基本的にNetty(Tomcatを使うとServletの非同期APIを利用)
Spring WebFluxCopyright © Acroquest Technology Co., Ltd. All rights reserved. 28PublisherMono Flux0 .. 1 個の要素をPublishする0 .. n 個の要素をPublishする
Spring WebFluxCopyright © Acroquest Technology Co., Ltd. All rights reserved. 29Mono• 0 .. 1 個のデータを発行• ストリーミング感ないけど、結構これだけで頑張れるFlux• 0 .. n 個のデータを発行• List に似ているが List ではない• List に変換しようとしてよくブロックする
Spring WebFlux• コールバックスタイルで処理をつないでいくCopyright © Acroquest Technology Co., Ltd. All rights reserved. 30Flux.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
Spring WebFlux• Pub/Subモデル(再掲)Copyright © Acroquest Technology Co., Ltd. All rights reserved. 31PublisherConsumer(Subscriber)observenotify
Spring WebFlux• 実行モデルCopyright © Acroquest Technology Co., Ltd. All rights reserved. 32Flux.just(“one”, “two”, “three”).map(String::toUpperCase).subscribe(System.out::println);PublisherSubscriber / SubscriptionSubscribersubscribesubscribeonNextonNext※色々省略しているので正確でないです
Spring WebFlux• 各処理は同じスレッドとは限らないCopyright © Acroquest Technology Co., Ltd. All rights reserved. 33Mono.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
Spring WebFlux• ControllerCopyright © Acroquest Technology Co., Ltd. All rights reserved. 34@RestControllerpublic 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を返す
Spring WebFlux• StreamCopyright © 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"}]ストリームになっていない?
Spring WebFlux• Content NegotiationCopyright © 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/streamdata:{"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"}
Spring WebFlux• ダメな例①Copyright © Acroquest Technology Co., Ltd. All rights reserved. 37@RestControllerpublic 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 してレスポンスを返却している。
Spring WebFlux• ダメな例②Copyright © Acroquest Technology Co., Ltd. All rights reserved. 38@RestControllerpublic 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) などを利用する
WebClient• ReactiveなHTTP Client➢ Non-BlockingかつReactiveなHTTP通信➢ ラムダ式を使ったFluent API➢ Mono/Fluxを戻り値に返す• RestTemplateの代替➢ WebClient単体で利用可能➢ 同期的な呼び出しも可能Copyright © Acroquest Technology Co., Ltd. All rights reserved. 39
WebClient• ExampleCopyright © Acroquest Technology Co., Ltd. All rights reserved. 40WebClient 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リクエストは実行されない
Reactive クライアント1. Reactive MongoDB2. Reactive Redis3. Reactive Cassandra4. Reactor KafkaCopyright © Acroquest Technology Co., Ltd. All rights reserved. 41
RDBへのアクセス?• ノンブロッキングAPIはサポートされていない• スレッドプールを別に用意して非同期呼び出しをしているケースが多い(Play2など)• JDBC Next: A New Asynchronous API forConnecting to a Databasehttps://www.slideshare.net/ypoirier/jdbc-next-a-new-asynchronous-api-for-connecting-to-a-databaseCopyright © Acroquest Technology Co., Ltd. All rights reserved. 42
Copyright © Acroquest Technology Co., Ltd. All rights reserved. 43https://www.slideshare.net/ArisaSasaki/jsug-20185-spring-io-108053900
Spring MVC or WebFlux?• 高スループットを出すならWebFlux• 実装しやすさはWebMVC• プログラミングモデルが異なるため、WebMVC -> WebFlux の書き換えは死ぬ(確信)• 現時点ではまだ “基本WebMVC” という選択になるが、そのうち “基本WebFlux” になるかもCopyright © Acroquest Technology Co., Ltd. All rights reserved. 44
Copyright © Acroquest Technology Co., Ltd. All rights reserved. 45Use Cases
Use Cases1. N + 1 問題Q:次の処理のレスポンスタイムは?Copyright © Acroquest Technology Co., Ltd. All rights reserved. 46商品サービス 在庫サービスFlux Mono5件の商品リストを返す パラメータの商品IDを見てその商品の在庫数を返す※ただし処理に1秒かかる
Use Cases1. N + 1 問題正解:Copyright © Acroquest Technology Co., Ltd. All rights reserved. 471.232sリクエストが並列で動いている
まとめ1. Blocking =2. Reactive でスループット↑↑3. RDBへのアクセスは現時点では4. 正直難しいので勉強しようCopyright © Acroquest Technology Co., Ltd. All rights reserved. 48
Copyright © Acroquest Technology Co., Ltd. All rights reserved. 49ご清聴ありがとうございました。Infrastructures Evolution