エンジニア的なネタを毎週書くブログ

東京でWebサービスの開発をしています 【英語版やってみました】http://taichiw-e.hatenablog.com/

JavaDayTokyo 2017 Report 2 : Reactive Stream

Reactiveなんちゃらというのがどうもわかりません。

という私が、Pivotalの槙さんのお話を聞いて、随分わかったかも!という気持ちになったセッション。
改めてブログにまとめなおしてみるとやっぱりわかってないところが多々あるのですが、ひとまず忘れないうちにメモを転記します。

発表資料はこちら。
Spring Framework 5.0による Reactive Web Application #JavaDayTokyo

BlockingとNon-Bloking

同期・非同期にかかわらず、基本的にJavaから他のI/O処理を呼び出した場合、レスポンスが返ってくるまでの間、呼び出し元のメインスレッドはお休み中になってしまいます(=Bloking)。
つまり、リソースの無駄遣いが発生するわけですが…

これと対照となるのが、イベントループを用いたNon-Blokingな処理。

イベントループは1スレッドで実行されるため、待ち処理の間に他のリクエストを捌くことができます。

これを実装しているアプリケーションサーバに、Nettyというサーバがあるそうです。
Appleでは35億65万台のNettyサーバが動いてるんだとか…。

Reactive Stream

Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure. ということで、「Reactive Stream」自体はinitiative(=そういう「動き」的なニュアンスなのかな?)らしいのですが

  • non-blocking
  • かつ back pressure
  • な 非同期処理の仕様を策定しよう!

という動きと解釈して良さそうです。

back pressure というのが肝で、Subscriber(データを受け取る方)が、自分の処理能力に合わせて、「これだけちょうだい」って依頼する考え方だそうで。
依頼したあとデータが送られてくるのは非同期な、NonBlockingな処理なのですが、こっちの都合を無視してバンバン投げつけてこられるわけではない という考え方のようです。

Ractor

Reactive Streamの実装としてPivotal社が開発しているのが、Reactor
他に、Reactive StreamとしてはRxJavaが有名ですが、RxJavaはJava6をベースにしているのに対し、ReactorはJava8ベースなのが一つの特徴とのことです。

Spring Framework 5.0でのReactive Spring

従来のSpringMVCはServletをベースにしているため、どうしてもBlockingなアプリケーションになってしまう。そこで、Spring WebFluxと言うものを新たに作りました!

返り値がFluxになっているだけで、従来のControllerと同じように使うことが可能。

その他、String以外のObjectや、Streamを返すことも可能とのこと。
Streamを返した場合、無限ストリームを返すことも可能だそうです。この場合でも、逐次処理なので、OutOfMemoryErrorになるようなことはないそうです。

この、無限ストリームを返す機能と、WebClient(Non blockingなHttpクライアント)を組み合わせると、例えば無限にTwitterのツイートを流し続けるようなアプリケーションも作ることが可能とのこと。

性能比較

リクエストを受けてから1秒Sleepしてレスポンスを返すようなアプリを、SpringMVCとSpring WebFluxで作ってみた場合。

Blockingアプリケーションの場合、1秒のスリープ中はスレッドが遊んでしまうにも関わらず、Blockされてしまうため、上限の200スレッドを超えたリクエストは待ちになってしまいます。

一方、NonBlockingなWebFluxの方は、リクエストごとにスレッドを作るわけではないため、TPSが200以上出ています。

実は、個人的にここ1-2年、よそのAPIを呼んで待ってるだけの、遊んでるスレッドは一つの課題でした。大してリソース食わないけどやたらスレッド数は増えちゃうし、先で詰まっちゃうと釣られて死んじゃう可能性があるし、それを避けるためにはサーキットブレーカーなり何なりが必要になるし…

ということで、発表中にもあったのですが、API Gatewayのような中間に挟まるアプリケーションにはすごく可能性がある話だと感じました!


なお、残念ながら、JDBCには現在Blockingなものしかなく、RDB接続をするアプリケーションの場合、完全にNonBlockingにするのは現時点では不可能、とのことでした。
(Java10で提案はあるそう)



ちょうど今の自分の課題にも関連しそうな技術なので、早めに手を動かしてみて、Updateしたいと思います。