Setsuna-0.0.2リリース~

SetsunaのVersion-0.0.2をリリースしました。


Github
Sourceforge.jpダウンロードページ


今回のリリースで一番大きな追加機能はServerモードの追加です。
0.0.1の時は、Setsunaにデータを入れる方法はパイプ入力しかなかったので、
コマンドラインで何かの出力をパイプでSetsunaに繋ぐしかなかったので、
Setsunaが動いているサーバ以外からデータをSetsunaに流せなかった
のが不便でした。そこでNetWork越しにデータを流せるようにこの機能を追加しました。


起動方法は簡単で"-server true"という表記を付けるだけです。ただServerモードの
場合はsetsuna.jar内に含まれないライブラリにも依存しているので従来の-jar指定での
起動は出来なくなっています。以下が起動サンプルです。


java -classpath ./:./lib/msgpack/*:setsuna.jar setsuna.core.SetsunaMain -server true
(※リリース物のsetsuna.jarがあるディレクトリで実行している想定です)
これでPort番号10028番でサーバで待ち受けています。
※起動ポート番号を変更する場合は"-bindport"オプションで変更できます。


で、今回Serverモードを実装するにあたってどのようなプロトコルと仕組みにしようか
悩んだのですが、独自に実装するのは止めて、MessagePack-RPCを利用しました。
MessagePack-RPCとても高速でありかつ、各言語のバインディングが作成されているため、
言語別でクライアントを別途作成する必要がないため、採用させていただきました。
MessagePack-RPCの詳しい情報はこちら


そして、サーバ側に定義されているリモートメソッドは以下になります。

int next (String[] sendData)
凄く単純にしました。パイプ入力をメソッド化したイメージです。
引数はデータをカラム単位で分解した後のデータを配列にして渡します。
つまり以下のPingの結果の場合

192.168.11.1 からの応答: バイト数 =32 時間 =16ms TTL=64
半角スペースでばらしてSetsunaに送り込みたい場合以下のような配列を渡すことになります。

String[] sendData = new String[7];
sendData[0] = "192.168.11.1";
sendData[1] = "からの応答:";
sendData[2] = "バイト数";
sendData[3] = "=32";
sendData[4] = "時間";
sendData[5] = "=16ms";
sendData[6] = "TTL=64";
今回も前回のSetsunaと同じで、Setsuna起動時に-columnオプションでカラム定義を決めれば
その定義に従って内部DBにテーブルが作られます。もし-columnを指定しなければ、最初に送られて
きたデータをもとに、テーブルが作られます。基本的に、入り口がパイプからMessagePackのサーバに
変わっただけで後の機能は全て同じ動きをします。


そして、サーバからの戻り値は3種類あります。

                                                                                        • -

0=データ入力成功
-9=カラム定義と送られてきたデータが合っていない
-1=サーバ側でエラー発生

                                                                                        • -

この戻り値を見て以降のクライアントでなんだかの処理をしてもらえればと思います。
実際にこれを送り込むJavaでのクライアント実装のサンプルはリリース物の
test/ServerClientSampleディレクトリのSetsunaServerModeClientSample.javaになります。
コードはこんな感じです。


1
2 import org.msgpack.rpc.Client;
3 import org.msgpack.rpc.loop.EventLoop;
4
5 /**
6 * Setsunaを"-server true"にて立ち上げた場合にデータを投入する

7 * Clientのサンプル.

8 * SetsunaのServerモードはMessagePack-RPCで出来ているため、

9 * ClientもMessagePack-RPCで作成する必要がある。

10 * Setsuna側には以下のメソッドが定義されているので

11 * それをに実装する.

12 * -- 定義メソッド ----------

13 * int next (String[] data)

14 * --------------------------

15 * 引数は1レコード当たりのデータを表す配列

16 * 戻り値は呼び出しの成否(0=正常終了, -9=カラム定義と合わない , -1=内部エラー)

17 *
18 * @author T.Okuyama
19 */
20 public class SetsunaServerModeClientSample {
21
22 /**
23 * SetsunaをRPC越しに呼び出し
24 * 渡す値はカラム数分のString値の配列.一貫して同じ長さ分を送ること
25 * 戻り値:正常終了 0, カラム定義と合わない -9, 内部エラー -1
26 */
27 public static interface RPCInterface {
28 /**
29 *
30 * @param data カラムデータの配列。必ずカラム数分必要
31 * @return int 結果:正常終了=0, カラム定義と合わない=-9, 内部エラー=-1
32 */
33 int next(String[] data);
34 }
35
36 public static void main(String[] args) throws Exception {
37 EventLoop loop = EventLoop.defaultEventLoop();
38
39 Client cli = new Client("localhost", 10028, loop);
40 RPCInterface iface = cli.proxy(RPCInterface.class);
41
42 String[] list = new String[3];
43 list[0] = "aa";
44 list[1] = "bb";
45 list[2] = "cc";
46 for (int i = 0; i < 1000; i++) {
47 // データを登録する
48 System.out.println(iface.next(list));
49 }
50 cli.close();
51 loop.shutdown();
52 }
53 }
このサンプルクライアントでポイントはまず、27行目〜34行目のリモートメソッドの定義で
上に示したサーバ側の定義をインプリしてます。そして37行目でEventLoopクラスを作成し39行目でクライアントを
Setsunaのアドレスとポートと先程のEventLoopを指定して作成。
そして次の40行目で、リモートメソッドを設定。
42行目〜45行目でSetsunaに渡したいデータを作成して、48行目でリモートメソッドを呼び出しています。


見てわかる通りMessagePack-RPCのおかげで非常に簡潔にかけます。
他言語のバインディングも本家サイトに出ているので、基本同じ要領だと思います。
これで他のサーバからデータが流せるので、イベント処理を集約出来ると思います。
ただ1台に集約するとそのサーバがこけたらどうするなどは今後の課題です。




この他の追加機能ですが、主にデバッグ系の機能と取り込みデータを
データベースにマッピングする辺りを強化しました。
デバッグ&Setsuna自身のログ機能
"-debug"オプション
前のバージョンではSetsunaにどのようなデータがAdapterで送り込まれ、どのようなTriggerが動き、どのようなSQL
検証用に流れどのようなUserEventが実行されたか分かりませんでした。さすがにSetsunaを利用して開発するうえで
これでは厳しいので、デバッグログを出せるようにしました。
"-debug"というオプション設定で出力されます。実際に指定すると以下のようになります。

ping -i 1 -c 1000 192.168.1.1 | grep --line-buffered ttl | java -jar setsuna.jar -debug on
指定してるは最後の"-debug on"という部分です。これでコンソールに標準入力から送り込まれたデータがデバッグされます。
以下のような感じになります。

Debug : Sat Mar 24 18:02:50 JST 2012 - - Pipe Input=[64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.237 ms]
{"COLUMN0":"64","COLUMN1":"bytes","COLUMN2":"from","COLUMN3":"192.168.1.1:","COLUMN4":"icmp_seq=1","COLUMN5":"ttl=64","COLUMN6":"time=0.237","COLUMN7":"ms"}
Debug : Sat Mar 24 18:02:50 JST 2012 - - Pipe Input=[64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.297 ms]
{"COLUMN0":"64","COLUMN1":"bytes","COLUMN2":"from","COLUMN3":"192.168.1.1:","COLUMN4":"icmp_seq=2","COLUMN5":"ttl=64","COLUMN6":"time=0.297","COLUMN7":"ms"}
Debug : Sat Mar 24 18:02:51 JST 2012 - - Pipe Input=[64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.245 ms]
デバッグで出力される文字列は先頭が"Debug"という文字始まる行が実際に送り込まれたデータ文字列です。
その他の"-trigger"、"-query"、"-event"、"-eventquery"で指定した内容や実行した内容も同じように
"Debug"が先頭について出力されます。
ただ、見ても分かるようにデバッグ以外の出力も混じっているので非常に見辛いです。
これを改善するのが、以下の指定です。

ping -i 1 -c 1000 192.168.1.1 | grep --line-buffered ttl | java -jar setsuna.jar -debug only
"-debug only"となっているのがその指定です。さきほどは"on"だった部分を"only"とすることで、以下のようになります。

Debug : Sat Mar 24 18:29:20 JST 2012 - - Pipe Input=[64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.263 ms]
Debug : Sat Mar 24 18:29:20 JST 2012 - - Pipe Input=[64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.243 ms]
Debug : Sat Mar 24 18:29:21 JST 2012 - - Pipe Input=[64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.229 ms]
デバッグのみの出力になっているのがわかってもらえると思います。


"-errorlog"オプション
このオプションはSetsunaが吐き出すエラー内容をファイルに出力するためのものです。
従来はコンソールにしか出なかったので、それをファイルに出力出来るようにしました。
以下のように指定します。

ping -i 1 -c 1000 192.168.1.1 | grep --line-buffered ttl | java -jar setsuna.jar -errorlog /var/log/setsuna_error
これで"/var/log/setsuna_error"にエラー出力が出るようになります。


インプットデータの読み込み開始レコード指定&カラム定義違いのデータを送り込んだ際に無視する指定
"-offsetオプション"
Setsunaにインプットされるデータを内部DBに取り込みを開始する位置をレコード数で設定できます。
設定は以下のようになります。このオプションは必ず"-column"オプションを指定する必要があります。

ping -i 1 -c 1000 192.168.1.1 | java -jar setsuna.jar -column "col1 col2 col3 col4 col5 col6 col7 col8" -offset 2
"-offset 2"の部分の指定です。これで、インプットされるデータの2レコード目から取り込まれます。
1行目はとりこまれず無視されます。
利用される想定は以下のようにpingのデータをSetsunaに送り込みたい場合

[setsuna]$ ping -i 1 -c 1000 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.277 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.278 ms
1行目のデータのフォーマットと2行目が異なるためそのまま取り込むとExceptionが発行されます。
これは"-column"指定で定義したカラム定義が8カラムあるのに対し1行目の
"PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data."をデフォルトの半角スペースで分解すると
以下のように7カラムしかないためです。

col1="PING"
col2="192.168.1.1"
col3="(192.168.1.1)"
col4="56(84)"
col5="bytes"
col6="of"
col7="data."
col8=データがない!!
このような場合に従来はgrepなどでSetsunaにデータを送り込む前に、不要なデータは省いてもらってたんですが、
このオプションを使うことで取り込み開始位置を調整することで、入力データのヘッダーをとばしたり出来ます。


"-skiperror"オプション
"-offset"は取り込み開始位置を調整できますが、取り込みを開始した出してから定義違いのデータがきた場合には
やはりExceptionが発生します。そこで"-skiperror"オプションを指定すると、途中に定義違いのデータが来た
場合にそのデータを取り込まずに無視します。以下のように指定します。

ping -i 1 -c 1000 192.168.1.1 | java -jar setsuna.jar -column "col1 col2 col3 col4 col5 col6 col7 col8" -skiperror true
最後の"-skiperror true"です。この指定は-columnの指定は必須ではありません。"-column"を指定しない場合は、
最初のレコードから自動的にカラム定義が作成されます。




以上が今回の追加機能です。これ以外にはいくつかの効率化とバグFixをしています。
追加機能も含めて全ての機能は"-help"オプションで確認してもらえます。
まだまだ、発展途上のプロジェクトなので、気軽にご意見いただけるとありがたいです!!
さあ、次は分散化でも考え始めるかな〜。