技術チームの竹内(@chimerast)です。
先日、Rx Ja Night 2016 #1という勉強会で、「RxJava + Vert.x + jOOλ で Microservice 的な何かを作ってみた」という題でLTしてきたので内容を少し書いてみようと思います。
当日は自分以外基本Android勢の発表で、サーバサイドの自分にとっては、とてもアウェイな雰囲気でしたがめげずに発表してきました。RxJavaっていうとサーバサイドでは普通は使う機会がないですからね。
今回作ったものとその問題点
ブラウザでチャートを描画するための元データとなるJSONを返すREST APIを作りました。
現在UZABASEではマイクロサービスアーキテクチャ的な何かのように、複数のREST APIを提供するサービスをぽこぽこ立ち上げており、その中の一つという位置づけです。
今回作ったChart APIの裏では、企業情報を扱う「Companies API」、統計情報を扱う「Stats API」、チャートそれぞれの線のデータ指定情報を管理する「Media API」という3つのAPIが動いています。これらにリクエストを投げて得たデータを元に最終的なチャートのJSONを構築します。
今回作る前から問題点として上がっていたのは、
- Chart APIだけがAWS上に配置され、それ以外がオンプレのデータセンター上にありデータセンター間通信となってしまうこと
- 最終的なレスポンスを返すまでに複数回(多いときには20回以上)バックエンドのAPIにリクエストを投げる必要があるということ
という二点です。
この状態で最速でレスポンスを返すためには、並列でバックエンドのAPIにリクエストを投げる必要がありますが、それを普通にブロッキングI/Oでやろうとすると、Chart APIへの1リクエストが10スレッド以上立ち上げてバックエンドAPIの返りを待つ必要があるという残念な状態になってしまします。
使ったもの
Vert.x http://vertx.io/
Nettyの上に作られ、ノンブロッキングI/Oで通信を行う事のできる高レベルAPI群です。サブプロジェクトがたくさんありDBとの通信を行うことの出来るモジュールなんかもあります。
これのサブプロジェクトの一つである、Vert.x-WebをつかってRESTなAPIをつくりつつ、バックエンドAPIに対して1スレッドからノンブロッキングで複数リクエストを投げるみたいな使い方をしました。
Vert.xの問題点として、全てがコールバックで返る非同期APIなため、例えば単純なDBのSELECT&UPDATEをするだけでも何段ものインデントが必要な書き方になります。メソッドを分けるという単純な解決法もありますが宣言的に書けるところは宣言的に書きたいです。
これを解決するためにRxJavaを使います。
RxJava https://github.com/ReactiveX/RxJava
RxJavaは、Streamとしての側面とPromiseとしての側面を併せ持ったライブラリです。いろいろな使い方ができ自分も全てのメソッドの使い道をうまく把握出来ていません。Android勢はJava8がまだ使えないためStreamの代わりとして使っていたり、非同期処理も多いのでPromiseとしての使い方をしたり色々しているようです。
今回のサーバサイドの開発では、Promiseとしての側面しか使っていません。コールバック地獄から抜け出すため(flatMap)、そして、複数の非同期処理をひとまとめにするため(zip)に主に使っています。
最終的には組み合わせて以下みたいなコードになっています。
感想
あまり長い文を書いても読みづらくなるだけなので、あとの細かい所はスライドを見てみてください。
Vert.xは巨大なモノリシックなサービスを作るのにはあまり向いていない気がしていますが、今回のように小さいサービスを作るには軽くて向いていると思えました。特に並列でバックエンドのAPIに丸投げして待つみたいなものを作る時にはスレッドの数を考える必要が無いという大きな利点があると思います。
RxJavaは非同期処理を気持ちよく書けるライブラリです。Vert.x、RxJavaともにJava8に対応しているためラムダ式でがしがし書くことができます。
エンジニア募集
株式会社ユーザベース、および、株式会社ニューズピックスではエンジニアを募集しています。ご興味があればお気軽にご連絡ください。