Skip to content

Instantly share code, notes, and snippets.

@rimms
Last active December 15, 2015 23:49
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rimms/5343003 to your computer and use it in GitHub Desktop.
Save rimms/5343003 to your computer and use it in GitHub Desktop.
Backup and Recovery

Backup and Recovery

Jubatus サーバは、メモリ上で機械学習に関するデータを管理しています。 メモリ上でデータを管理するという性質上、Jubatusサーバプロセスの終了とともに Jubatus 上のデータは失われます。

Jubatus では、予期せぬプロセスの終了や誤ったオペレーションに備え、バックアップとリカバリのための機能を提供しています。

現在、Jubatus では、以下の手段を提供しています。

  • save_and_load

Save and Load

Jubatus サーバの内部状態をファイルに保存し、そのファイルを読み込むことで、Jubatus サーバの内部状態を復元する機能です。

Jubatus では、この機能をクライアント向けに MessagePack-RPC インタフェースで提供しています。

現在、内部状態を保存した環境と異なる環境(クラスタ構成台数)への復元はサポートしていません。

Save

Save は、クライアントからの save という RPCメソッド の呼び出しにより Jubatus サーバの内部状態をファイル出力する機能です。

Save を実行中は、メモリ上の機械学習モデルへの書き込みの制限を行うため、いかなる RPC メソッド呼び出しもファイルの出力完了まで待たされることになります。

ファイルの出力先は、Jubatus サーバの起動オプション -d, --datadir で指定することができ、標準では /tmp が設定されます。

ファイルは、以下の命名規則に従ったファイル名で出力されます。すでに同じ名前のファイルが存在する場合、ファイルの上書きを行うため、save メソッドの引数には十分に注意する必要があります。

${IPADDR}_${PORT}_${TYPE}_${ID}.jubatus
${IPADDR} Jubatus サーバが RPCリクエストを受け付ける Ipv4 アドレス
${PORT} Jubatus サーバが RPCリクエストを受け付ける ポート番号
${TYPE} 機械学習タスク名 (classifier, recommender, ...)

${ID}

save メソッドの引数
a-zA-Z0-9- からなる 100文字

Save で出力されたファイルは、Jubatus のバージョンに依存する形式で出力され、互換性のあるバージョンの Jubatus でしか後述する Load を行うことができません。

現在の出力フォーマットは savedata_format を参照して下さい。

Load

Load は、Save で作成されたファイルを読み込み、Jubatus サーバの内部状態をファイルに保存された状態へ復元する機能です。クライアントからの load メソッドコールにより実行されます。

Load の実行中は、メモリ上の機械学習モデルへの書き込みの制限を行うため、Save と同様に、いかなる RPC メソッド呼び出しも処理完了まで待たされることになります。

ファイルの読込先は、Jubatus サーバの起動オプション -d, --datadir で指定することができ、標準では /tmp が設定されます。

save メソッドでの引数で指定した ${ID}load メソッドの引数に指定することで、読み込み対象のファイルを指定します。

ファイルの読み込み時、Jubatus サーバは以下のチェックを行い、バージョンの互換換性や復元対象の Jubatus サーバの内部状態との比較を行います。

現在の出力フォーマット と 比較内容 は savedata_format を参照して下さい。

SaveData Format

Save により出力される情報は、大きく headersystem_data_containeruser_data_container の 3のブロックに分けられています。

system_data_containeruser_data_container は、それぞれ、機械学習タスクに依存しない情報 と 機械学習に依存する情報 を msgpack 形式で出力しており、フレームワークを利用して、あらたな機械学習タスクを実装する場合は、独自の user_data_container を定義・実装する必要があります。

マルチバイト値はビッグエンディアンで読み書きを行います。

Item Size Description
header 48 Byte ヘッダー情報
system_data_container 全機械学習タスクで共通の情報 [msgpack 形式]
user_data_container 機械学習ごとに定義するコンテナ [msgpack 形式]

header

header は、ファイル自体の情報 を管理し、主にファイル読み込み時のチェックに利用します。

  • magic_number : 'jubatus\0' と一致することを確認します。
  • format_version : 動作している Jubatus サーバの format_version と比較し、互換性があることを確認します。
  • jubatus_version : 動作している Jubatus サーバの jubatus_version と比較し、互換性があることを確認します。
  • crc32 : crc32 を除くエントリの CRC32 値と比較を行います。

system_data_container

system_data_container は、以下の通り 機械学習タスクに依存しない情報 を管理します。 将来的な拡張に備え、構造体として定義しています。

現時点では、動作している Jubatus サーバー に情報を取り込むことは行わず、動作している Jubatus サーバー の情報との確認のみに利用します。

Item Type Description
version uint64_t コンテナのバージョン番号
timestamp time_t タイムスタンプ(UNIX epoc time)
type string 機械学習タスク名
id string save メソッドの引数
config string 設定ファイルの内容
  • version : 動作している Jubatus サーバの system_data_container の version と比較し、互換性があることを確認します。
  • type : 動作している Jubatus サーバの 機械学習タスク名 と一致していることを確認します。
  • config : 動作している Jubatus サーバの設定ファイルの内容と比較を行います。現時点では、セマンティクスレベルのチェックではなく、string の完全一致のみを確認します。一致していない場合は、警告ログを出力し、Load の処理を継続します。

TBD

  • 起動時Load を実現するため、set_config するほうが良いか? 保存対象が config の内容に依存してくることが十分に考えられるので、set_config するのも良いと考えているが、引数に指定した config が意味を成さないのは、set_config を廃止した経緯と反するのでは。起動時 Load の対応の際に、議論が必要。

user_data_container

user_data_container は、機械学習に依存する情報 を管理し、機械学習タスクごとに独自に定義を行います。

独自に定義する情報とは別に、以下の情報を共通で管理します。独自に定義した情報は動作中の Jubatus サーバー に取り込みを行います。

Item Type Description
version uint64_t コンテナのバージョン番号

既存の機械学習タスクの保存対象は以下に示すとおりです。

classifier

  • mixable_weight_manager
    • weight_manager
  • linear_function_mixer
    • (standalone mode) local_storage
    • (distributed mode) local_storage_mixture

recommender

  • mixable_weight_manager
    • weight_manager
  • rcmdr
    • recommender_base
      • sparse_matrix_storage (生データ)
      • アルゴリズム固有
        • (minhash) bit_index_storage
        • (inverted_index) inverted_index_storage
        • (lsh) bit_index_storage, ...
        • (euclid_lsh) lsh_index_storage, ...

regression

  • mixable_weight_manager
    • weight_manager
  • linear_function_mixer
    • (standalone mode) local_storage
    • (distributed mode) local_storage_mixture

stat

  • mixable_stat

graph

  • mixable_graph
    • graph_base

anomaly

  • mixable_weight_manager
    • weight_manager
  • mixable_anomaly
    • anomaly_base
      • sparse_matrix_storage (生データ)
      • lof_storage

TBD

  • user_data_container は継承関係が多い内部構造を出力するために、以下の様に msgpack 形式 の情報を続けて出力している。内部モジュール構成の見直し時に、これを簡単な定義を行えるようにしたい。
[1] // version
[member, member, member] // model

以下のように 1つ の構造として出力できるようになれば、フレームワーク利用者の定義(実装)も容易にできると考える。

[
  [1] // version
  [member, member, member] // model
]
  • 保存対象が十分かの検討
    • stat: window_size を保存しているが set_config されるので、必要ない
    • stat: stats_ を保存対象に含める必要がある
    • graph, anomaly: global_id_generater を保存すべきだが、zk 有り無しで分岐が必要。場合によっては、zk上の値も復元する必要もある。

Define User Data Container

user_data_container は、各機械学習タスクごとに実装します。

以下に、実装例を示します。

driver/task.hpp

class task_data : public user_data_container {
  // 保存対象とするメンバの定義
  target model;
  target fv_converter;

  // コンテナのバージョン番号を定義する
  uint64_t current_version() const {
    return 1;
  }

  // msgpack 形式への変換
  void pack(msgpack::sbuffer& buf) const;

  // msgpack 形式からの変換
  void unpack(msgpack::unpacker& unpacker);
}

class task {
  task_data data_;
}

driver/task.cpp

user_data_.reset(&data_);

void task_data::pack(msgpack::sbuffer& buf) const {
   msgpack::pack(buf, *this);
   model.pack(buf);
   fv_converter.pack(buf);
}

void classifier_data::unpack(msgpack::unpacker& unpacker) {
   msgpack::unpacked msg;
   unpacker.next(&msg);
   model.unpack(msg);
   unpacker.next(&msg);
   fv_converter.unpack(msg);
}

target

  • 保存対象となる model や fv_converter は pack と unpack のメソッドを実装し、自身のシリアライズ、デシリアライズをできるようにします。
void pack(msgpack::sbuffer& buf) const {
  msgpack::pack(buf, *this);
}

void unpack(msgpack::unpacked& msg) {
   msg.get().convert(this);
}
@rimms
Copy link
Author

rimms commented Apr 22, 2013

stat の保存対象に stats_ を追加 (See. jubatus/jubatus#320)

@kmaehashi
Copy link

SaveData Format

データ構造の表に型情報が欲しいです (unsigned?)。

jubatus_version: 動作している Jubatus サーバの jubatus_version と比較し、互換性があることを確認します。

互換性は、ファイルフォーマット + 構造体のバージョン情報の比較で担保されるのでは?

config: 動作している Jubatus サーバの設定ファイルの内容と比較を行います。現時点では、セマンティクスレベルのチェックではなく、string の完全一致のみを確認します。一致していない場合は、警告ログを出力し、Load の処理を継続します。

意見が分かれそうですが、set_config廃止の経緯も踏まえると、デフォルト安全側に倒したい気もします。

Define User Data Container

簡単に書けるマクロを用意したいですね。

@gintenlabo
Copy link

crc32crc32 を除くファイル全体の CRC32 値

この CRC32 値は, crc32 フィールドの部分が切り詰められた仮データ,言い換えると, jubatus_version の直後に system_data_size が来る,本来のデータより 4 byte だけ短いような仮データに対する CRC32 値という認識でよいでしょうか?

crc32 フィールドが 0 で埋められた,本来のデータと同じ長さの仮データに対する CRC32 値という解釈も 不可能ではないので,一応 確認まで.

@gintenlabo
Copy link

jubatus/jubatus#475 (comment)

とりあえず読み込み時に限り id として空文字列が渡された場合, id をチェックしないことにしたいと思います.
その場合,書き込み時に id として空文字列が渡された場合には,例外を投げるようにするのが良いと思いますが,どうでしょうか

@suma
Copy link

suma commented Oct 16, 2013

crc32

オフラインかチャットで返答済みだと思いますが(ここにコメントしてなかったので遅れましたが書きます)、切り詰められた仮データで良いと思います。

id

読み・書き(framework::server_save, framework::saver_load)共にその振る舞いで良いと思います。

@rimms
Copy link
Author

rimms commented Oct 16, 2013

id ですが、起動時ロード や ファイル名を変更して別の場所に保管しておくというようなバックアップ運用 を想定すると、ファイル名の id(引数の id) と ファイル内の id をチェックすることで、利用ケースが限られてしまうのではと思います。

そもそも id をファイル内に含める必要性があったかという話もあるんですが、現状は、メタな情報としてチェックには利用しないという扱いで良いと思います。

@rimms
Copy link
Author

rimms commented Oct 16, 2013

あ、申し訳ないです。一部勘違いしていました。訂正します。

「空文字 = 起動時ロード」を想定しているということですね。

ファイル名を変更して別の場所に保管しておくというようなバックアップ運用

これはあくまで、想定される運用の話なので、実際にはどう運用されるかはこちらで決めて良い話ですので「ファイル名を変更するとloadできなくなる」という仕様で縛って良いと思います。

ですので、 https://gist.github.com/rimms/5343003/#comment-930271 の振る舞いで良いと思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment