Jubatusの分散モードで知っておきたい少しのこと 

この記事は [Jubatus Advent Calendar 2016](http://qiita.com/advent-calendar/2016/jubatus) の13日目です。

本記事では、Jubatus の分散モードについての説明と注意事項などをまとめたいと思います。

# 分散モードとは

Jubatus は、スループットを向上させるために「分散モード」というクラスタ構成で運用することができます。

Jubatus サーバ のみで稼働させる「スタンドアロンモード」でも十分な性能が期待できますが、Jubatus サーバ と Jubatus プロキシ、[Apache ZooKeeper](https://zookeeper.apache.org/) による「分散モード」を使うと、スループットと耐障害性を向上させることができます。

「分散モード」のアーキテクチャ、概念、利用方法は、公式サイトの以下が参考になります。

* [アーキテクチャ概要](http://jubat.us/ja/overview/architecture.html)
* [分散学習機構Mixの概念説明](http://jubat.us/ja/overview/mix.html)
* [チュートリアル: 分散モード](http://jubat.us/ja/tutorial_distributed.html)

# 分散モード運用時の注意点

前述の公式サイトにも記載されていますが、「分散モード」を運用する上で、注意しなくてはいけないことを少し説明します。

## ZooKeeper の運用

「分散モード」では、Jubatus サーバ、Jubatus プロキシ の各プロセスは、ZooKeeper 上で管理され、死活監視が行われます。

簡単に説明すると以下のような感じです。

1. Jubatus サーバ を起動すると、 ZooKeeper 上に ``IPアドレス_ポート`` というノード識別子 [^1] が追加される。
2. Jubatus サーバ が停止すると、 ZooKeeper 上の ノード識別子 が自動的に削除される。

Jubatus サーバ のプロセスの監視はこのように行っており、タイミングにもよりますが、停止した Jubatus サーバに対して、Jubatus プロキシからリクエストが転送されるということは、発生しにくいようになっています。

運用上、問題となるのは ZooKeeper が停止したときです。
ZooKeeper が停止すると、この ZooKeeper に接続している Jubatus サーバ と Jubatus プロキシ は、協調動作ができないと判断し、 **自らプロセスを停止** します。

そのため、 Jubatus を「分散モード」で動作させるときには、以下を推奨しています。 [^2]

1. ZooKeeper は冗長化(アンサンブル構成)して運用する
2. ZooKeeper のパフォーマンスが低下しないように、ZooKeeper 専用のマシンを用意する

# 分散モードで理解しておきたいこと

「分散モード」で、理解しておきたいことをいくつかピックアップして紹介します。

## プロキシの転送処理

まず、はじめに理解しておきたいのは、Jubatus プロキシのリクエスト転送処理です。

Jubatus 1.0.0 現在、Jubatus プロキシには、Jubatus サーバの負荷情報を確認してリクエストを転送するロードバランシングのような機能は存在せず、以下の 3種類 を提供しています。[^3]

| 転送方式                                                                                                       | IDLにおける表記法 |
|:---------------------------------------------------------------------------------------------------------------|:------------------|
| すべての Jubatusサーバ へリクエストを転送する                                                                  | ``broadcast``     |
| ランダムに選択されたいずれか1台の Jubatusサーバ へリクエストを転送する                                         | ``random``        |
| Consistent Hashing にもとづいて Jubatusサーバ を選択し、リクエストを転送する(RPCメソッドの第1引数をキーとする) | ``cht``           |

各機械学習エンジン、各RPCメソッドにどの転送方式が採用されているかは、実は、公式サイトには掲載されていません。 :see_no_evil:
[ここ](https://github.com/jubatus/jubatus/tree/master/jubatus/server/server) にある ``.idl`` という拡張子のファイルに書いてあるアノテーションから確認することができます。(機械学習エンジンのデータの持ち方や各RPCの利用シーンを想定して設定されています)

## MIX （ゆるやかなモデル共有）

前述で紹介した公式サイトのページにもあるとおり、「分散モード」では、「MIX」という処理が動きます。

「MIX」は、 **ゆるやかなモデル同期** を行う機能で、同一時刻において同じモデルが全サーバノードで共有されていることを保証しない という割り切った処理です。そのため、学習(登録)したデータをもれなく正確に返却する必要があるような利用シーンでは、「分散モード」ではなく「スタンドアロンモード」で利用することを推奨します。（機械学習の利用シーンでは、そのようなケースはあまり無いかもしれませんが）

これがどういうことかということを、前述の Jubatus プロキシ の転送方式 も加味して説明します。

以下のような Jubatus クラスタ を想定します。

* 機械学習エンジン: 推薦 (``jubarecommender``)
* Jubatus サーバ数: 3
* Jubatus プロキシ数: 1

上記のクラスタに対して、データの追加(``update_row``) と 推薦(``similar_row_from_datum``) を行うようなケースでは、以下のようなことが起こりえます。

1. ``hoge`` という ID のデータを追加する:
    1. クライアント から Jubatus プロキシ に対して、``update_row("hoge", datum)`` をリクエストする。
    2. ``update_row`` のリクエスト転送方式は、 ``cht`` であるため、Jubatus プロキシは、 Jubatus サーバ のなかから**CHTにもとづいて**ノードを選択し、リクエストを転送する。
    3. 2 で選択された Jubatus サーバに ``hoge`` という ID のデータが追加される。

2. MIX が行われる前に 推薦結果 を取得する:
    1. クライアント から Jubatus プロキシ に対して、``similar_row_from_datum(datum)`` をリクエストする。
    2. ``similar_row_from_datum`` のリクエスト転送方式は、 ``random`` であるため、Jubatus プロキシは、 Jubatus サーバ のなかから**ランダム**にノードを選択し、リクエストを転送する。 => このとき ``update_row`` が通知されていないノードが選択されたとする
    3. 2 で選択された Jubatus サーバのモデルを参照して、結果を返却する。 => モデルにデータが存在しないので ``hoge`` という ID は返却されない

と、このように データの追加(``update_row``) と 推薦(``similar_row_from_datum``) では、リクエストの転送方式が異なるので、Jubatus クラスタに対してデータを追加したつもりでも、分析結果には追加したはずのデータが含まれていないという状況が発生することになります。(補足: MIX が行われた後だったら、このようなことは発生しません)

# まとめ

Jubatus の「分散モード」をテーマに公式サイトのリンクを交えながら、運用上の注意点 や 理解しておきたい仕様 を簡単に紹介しました。
「スタンドアロンモード」だけでこと足りることも多いですが、「分散モード」もぜひ使ってみてください。

明日は @torash さんの記事です。お楽しみに!

最後に... 文字ばっかりになってしまい、ごめんなさい。

---

[^1]: Jubatus プロキシでは、この ノード識別子 の一覧を参照し、リクエストを転送する先を決定する。
[^2]: ZooKeeper の運用については、[ZooKeeper の公式ドキュメント](https://zookeeper.apache.org/doc/trunk/zookeeperAdmin.html) を参考にしましょう。
[^3]: この情報は、公式サイトの [コード生成器の利用](http://jubat.us/ja/developers/server.html) に掲載されています。