日本OSS奨励賞を受賞しました

このたび、独立行政法人 情報処理推進機構 日本OSS奨励賞を受賞いたしました。ITPro
他に受賞された方々の名前を拝見すると恐縮ではありますが、高く評価していただいたことを大変光栄に思います。


受賞理由は、「分散Key-valueストアである「kumofs」を開発し、OSSとして公開している」ことと、「MessagePackを精力的に開発し、こちらもOSSとして公開している」ことの2点で、新たに開発したオープンソースソフトウェアを公開している点を評価していただいたようです。


kumofsを共に開発したえとらぼ株式会社の皆様、そしてコミュニティの方々に感謝します。

また、MessagePackのコミットログを見ると分かりますが、MessagePackの各言語版の実装は私の手によるものではなく、各言語のエキスパートの方々によって実装されています。
先日にもMessagePack for Java 0.4をリリースしたところですが、これからもガツガツと 設計 & 実装 & 宣伝 を実施していきたいと思っているところです。


MessagePack for Java 0.4 開発版リリース!

バイナリシリアライズ形式 MessagePackJava版の最新版をリリースしました!
新しいAPIを大量に追加し、使い勝手が大幅に向上しています。


今回は開発版のリリースで、安定版のリリースはもう少し先になります。
こういうAPIの方が良いのではないか、ここの実装にバグがある、このコードはもっと最適化できる、こんな用途に使ってみた などなど、フィードバックをお待ちしていますm(_ _)m


ここでは極めて重要な新機能である、

  • 動的コード生成
  • optionalフィールド
  • 動的型付けオブジェクト
  • テンプレート

について紹介します。

動的コード生成

リフレクションを使うと、クラスからメンバ変数の一覧を取得することができ、ユーザー定義のクラスをシリアライズ・デシリアライズできるようになります。これは非常に便利で、わざわざシリアライズ用のメソッドを自前で実装することなく、オブジェクトを渡すだけでシリアライズできるようになります。
しかし、リフレクションは遅いという重大な欠点があります。


そこで MessagePack では、リフレクションで取り出した情報を元にJavaのコードを生成し、それを実行時にコンパイル・リンクすることで、シリアライズ速度を大幅に高速化します。

使い方は↓このようになります。単にオブジェクトを渡すだけでシリアライズでき、クラスを指定するだけでデシリアライズできます:

import org.msgpack.MessagePack;
import org.msgpack.annotation.MessagePackMessage;

public class Main {
    // ユーザー定義のクラス
    // アノテーションを付ける
    @MessagePackMessage
    public static class MyClass {
        public String str;
        public double num;
    }

    public static void main(String[] args) {
        MyClass src = new MyClass();
        src.str = "msgpack";
        src.num = 0.4;

        // シリアライズ
        byte[] raw = MessagePack.pack(src);

        // デシリアライズ
        MyClass dst = MessagePack.unpack(raw, MyClass.class);
    }
}

とても簡単ですね! 革命的な使いやすさです。
このようにアノテーションを付けるだけで、高速にシリアライズ・デシリアライズができます。


何かの事情でアノテーションを付けられない場合でも、事前に登録しておけば同じ効果が得られます。

        // ユーザー定義クラスを事前に登録しておく
        MessagePack.register(MyClass.class);


動的コード生成機能の実装は、分散Key-valueストア「ROMA」の開発者としても知られる @muga_nishizawaさんによるものです。実はJavaで定番の動的コード生成ライブラリであるJavassistの開発者でもあったようです。

optionalフィールド

データの寿命は、プログラムの寿命より長いことがあります。
このためデータとプログラムはできるだけ分離しておくのがセオリーとされますが、ここでデータとプログラムの間に立つシリアライザは、悩ましい問題を抱えることになります。プログラムが変更され、データのフォーマットが変更されたときでも、残されている古いデータも正しく扱えなければなりません。


この問題に対して MessagePack では、オブジェクトをシリアライズシリアライズしているとき、互換性を保ったままメンバフィールドを追加できるようにする仕組みを提供します。

まず↓このようなクラスがあったとします:

@MessagePackMessage
public static class MyClass {
    public String str;
    public double num;
}

この定義に従ってシリアライズされたデータがたくさん蓄積されていたり、この定義に従って動いている再起動したくないサーバがあるとします。
これらとの互換性を保ったまま、クラスの定義を↓このように変更することができます:

@MessagePackMessage
public static class MyClass {
    public String str;
    public double num;

    // 新しいフィールドをオプショナルとして追加
    @MessagePackOptional
    public int flag = 0;
}

新しく追加したフィールドにはアノテーションを付け、optionalなフィールドにします。


この定義に従って古いデータを読み込むと、optionalなフィールドにはデフォルト値が設定されます。
逆に、新しいフィールドが追加されているデータを古いコードで読み込むこともできます。その場合は新しいフィールドは単に無視されます。これによって古いサーバと新しいサーバが相互に通信することができます。ローリングアップデートができますね。

動的型付けオブジェクト

MessagePack は、シリアライズ後のバイト列にオブジェクトの「型」を保存します。このバイト列をデシリアライズする側から見ると、デシリアライズ時=実行時に型が決定される動的型付けの性質を持っていると言えます。
例えば Ruby は動的型付け言語なので、このデータそのまま扱えるのですが、Java は静的型付け言語なので、そのままではうまく扱えません。具体的に言えば、デシリアライズされたオブジェクトの型が Object だと非常に使いにくいです。


そこで MessagePack では、動的型付けオブジェクトテンプレート という2つの機能を提供します。


まず MessagePackObject は、動的に型付けされたオブジェクトを表現するクラスです。
MessagePack.unpack(byte[] buffer) などのデシリアライズAPIの返り値は、このMessagePackObjectになります。このクラスは、実際の型を検査するメソッド(isIntegerType()isListType()など)や、静的な型に変換するメソッド(asString()convert(Template)など)を持っています。

MessagePackObject を使うことで、コンパイル時には知り得ない未知のデータ をうまく取り扱うことができます。

テンプレート

テンプレートは、デシリアライズされたオブジェクトを静的な型に変換する機能を提供します。同時に型チェックを行い、想定外のデータだったら例外(MessageTypeException)を投げます。
テンプレートは↓このように使います:

import java.util.ArrayList;
import java.util.List;

import org.msgpack.MessagePack;
import static org.msgpack.Templates.*;

public class Main {
    public static void main(String[] args) {
        // シリアライズするオブジェクトを作成
        List<String> src = new ArrayList();
        src.add("msgpack");
        src.add("kumofs");
        src.add("viver");

        // バイト列にシリアライズ
        byte[] raw = MessagePack.pack(src);

        // 方法1: テンプレートを指定して直接デシリアライズ
        List<String> dst1 = (List<String>)MessagePack.unpack(raw, tList(TString));

        // 方法2: いったん動的型付けオブジェクトにデシリアライズしてから型変換
        MessagePackObject dynamic = MessagePack.unpack(raw);
        List<String> dst2 = (List<String>)dynamic.convert(tList(TString));
    }
}

テンプレートは org.msgpack.Templates.* に定義されており、import static すると tList(Template elementTemplate)tArray(Template elementTemplate)TStringTIntegerなどのテンプレートが使えるようになります。

使い方

多くの機能は org.msgpack.MessagePack クラスで使えるようになっています:

package org.msgpack;
public class MessagePack {
    public static byte[] pack(Object obj);
    public static byte[] pack(Object obj, Template tmpl) throws MessageTypeException;
    public static void pack(OutputStream out, Object obj) throws IOException;
    public static void pack(OutputStream out, Object obj, Template tmpl) throws IOException;

    public static MessagePackObject unpack(byte[] buffer) throws MessageTypeException;
    public static MessagePackObject unpack(InputStream in) throws IOException;
    public static Object unpack(byte[] buffer, Template tmpl) throws MessageTypeException;
    public static Object unpack(InputStream in, Template tmpl) throws IOException, MessageTypeException;
    public static <T> T unpack(byte[] buffer, Class<T> klass) throws MessageTypeException;
    public static <T> T unpack(InputStream in, Class<T> klass) throws IOException, MessageTypeException;

    public static void register(Class<?> target);
    public static void register(Class<?> target, Template tmpl);
    public static void registerPacker(Class<?> target, MessagePacker packer);
    public static void registerConverter(Class<?> target, MessageConverter converter);
    public static void registerUnpacker(Class<?> target, MessageUnpacker unpacker);
}

インストール

MessagePack for Java 0.4-devel は、mavenを使ってインストールできます。
mavenリポジトリhttp://msgpack.org/maven2/org/msgpack/msgpack/ にあります。*1
ソースコードhttp://github.com/msgpack/msgpack にあります。


フィードバックはTwitterでお気軽に!

現在のJava版のメンテナは@muga_nishizawa@frsyukiで捕捉できます。

メーリングリストとIRCもあります。ぜひどうぞ。MessagePack Users


The MessagePack Project

*1:javassistのバージョン3.12.1.GA以降に依存しています。javassistは[https://repository.jboss.org/nexus/content/groups/public/:title=JBossのmavenリポジトリ]にあります。

RubyKaigi2010でトークしてきました - The MessagePack Project

つくばで開かれたRubyKaigi2010で、多言語間通信ライブラリ MessagePack についてLTしてきました。
音声付きの動画をニコニコ動画で見られます(スバラシイ!)。ぴったり5分に収まりました^^;



Twitterを見る限りでは評判も良かったようで、ひとまず安心しています。

説明が足りなかった部分もあるので、ここで補足しておきます。

JSONと比べてどれくらい小さくなるの?

ある日のTwitterのpublic_timelineを使って比較してみたところ、JSONでは31KBだったものが、MessagePackでシリアライズし直すと25KBになり、約19%削減されました。

ただミニブログサービス「Amebaなう」に…等々の話にもあるように、「MessagePackを使えば必ず大幅にサイズ圧縮に成功する」という訳ではないです。
例えば、大半がASCII文字列で埋まっているようなJSONはほとんど小さくなりません。バイナリデータを含んでいたり(JSONではBASE64などでエンコードする必要がある)、複雑な構造を持つデータが特に小さくなります。


Amebaなうでの事例はjust do neetさんのブログに詳しく取り上げていますので、ぜひご覧ください:LuceneのインデックスにStoreするデータをMessagePackで圧縮してみた

なぜJSONと比べて小さくなるの?

よく使われるデータほど少ないバイト数でシリアライズするようになっているためです。他にも型を表すバイトにデータ自体を埋め込んでサイズを削減するなどの工夫をしています。
例えば-31〜128の小さい整数は1バイト、要素数が15個までの小さな配列や連想配列1バイトで表します。truenullなどの要素も1バイトです。

極端な例では、{"a":true}という連想配列は、JSONでは10バイトも必要ですが、MessagePackでは4バイトで済みます。
MessagePackの詳しい仕様については、MessagePack format specificationを参照してください。

なぜJSONと比べて速いの?

JSONやXMLはテキストフォーマットなので、文字列のエスケープ処理(やエスケープ解除処理)に時間がかかります。文字列が長ければ長いほど、線形に処理時間が増えていきます。
このため、長い文字列を含んだデータではMessagePackの方がずっと高速になります。
大きな画像データを扱う用途にJSONを使う気にはなりませんが、MessagePackなら効率よく扱えます。画像にメタデータを付与して保存しておきたい場合などなど。


RailsのログファイルをMessagePackで超高速解析!もご覧ください。

RPCのサーバ側はどう書くの?

↓これで動きます。

require 'msgpack/rpc'    # gem install msgpack-rpc

class KVServer
  def initialize
    @hash = {}
  end

  def get(key)   # publicなメソッドがRPCで呼べるようになる!
    @hash[key] # @hashからkeyを取り出して返す
  end

  def set(key, value)
    @hash[key] = value  # @hashにkey-valueをセット
  end
end

# MessagePack::RPC::Server#listen(アドレス, ポート番号, インスタンス)
svr = MessagePack::RPC::Server.new
svr.listen('0.0.0.0', 18800, KVServer.new)
svr.run   # イベントループ開始

publicなメソッドをリモートから呼び出すことができます。
これで簡単なKey-valueストアができました。全部で54行もあれば分散KVS(レプリケーション機能付き)を実装することができます。

コネクションプーリングはどうやって使うの?

↓こうやって使います。

require 'msgpack/rpc'    # gem install msgpack-rpc

# SessionPoolを作成
$ws = MessagePack::RPC::SessionPool.new

# セッションを取得(初めてなら自動的に作成される)
session = $ws.get_session("127.0.0.1", 18800)

# Client < Session
p session.call(:get, "key1")

WebSocketでブラウザにプッシュ配信する - MessagePack-RPC+Rev-WebSocketで具体的な使い方を紹介しています。

コネクションが切断されたらどうなる?

自動的に再接続します(Thriftとは違って)。

どこで使われているの?

実はあなたのそばにもMessagePack。

もっと詳しく知るには?

MessagePackのWikiや、Twitter#msgpackタグをウォッチしてみてください。
ソースコードリポジトリgithubにあります。 
RDocはここです:シリアライズ RPC


Ruby版のメンテナンスは私が行っています。何か疑問などなどあれば @frsyuki までどうぞ^^;

WebSocketでブラウザにプッシュ配信する - MessagePack-RPC+Rev-WebSocket

先日、WebSocketのサーバライブラリ Rev-WebSocket をリリースしました。
前回のエントリではブラウザ同士で通信するチャットアプリケーションを紹介しましたが、実際にはTwitterクローラやWebアプリケーションなど、別のプログラムと連携してブラウザにプッシュ配信したくなると思います。

つまり↓このように、任意のプログラムからWebSocketサーバを経由して、ブラウザにデータをプッシュ配信します:


http://github.com/frsyuki/rev-websocket


プッシュ配信したいアプリケーションと WebSocket サーバの間は MessagePack-RPC で繋ぎます。
Rev-WebSocket と MessagePack-RPC は相性が良く、簡単に統合することができます*1


アプリケーションから WebSocket サーバを経由してブラウザにデータを配信するコードは、↓このようになります。

require 'rubygems'
require 'msgpack/rpc'    # gem install msgpack-rpc
require 'json'

# WebSocketサーバへのRPCセッションを作成
$ws = MessagePack::RPC::Client.new('127.0.0.1', 18800)

# プッシュ配信
$ws.call(:push_data, {"hello" => "world"}.to_json)

簡単ですね! ここではRubyを使っていますが、MessagePack-RPCが対応していれば他の言語からも配信できます(C++JavaPerlなど)。
$ws はどこからでも使い回せます。


WebSocketサーバは↓このようになります。

require 'rubygems'
require 'rev/websocket'  # gem install rev-websocket
require 'msgpack/rpc'    # gem install msgpack-rpc

$sockets = {}

class MyConnection < Rev::WebSocket
  # 接続されたら呼ばれる
  def on_open
    puts "WebSocket opened from '#{peeraddr[2]}': request=#{request.inspect}"
    $sockets[self] = self
  end

  # メッセージが届いたら呼ばれる
  def on_message(data)
    puts "WebSocket data received: '#{data}'"
  end

  # 切断されたら呼ばれる
  def on_close
    puts "WebSocket closed"
    $sockets.delete(self)
  end
end

class RPCServer
  # すべてのブラウザに配信
  def push_data(data)
    $sockets.each_value {|sock|
      sock.send_message(data)
    }
    nil
  end
end

# イベントループを作成
loop = Rev::Loop.default

port = ARGV[0] || 8080

# イベントループにWebSocketサーバを登録
ws = Rev::WebSocketServer.new('0.0.0.0', port, MyConnection)
ws.attach(loop)

# 同じイベントループにRPCサーバも乗せる
rpc = MessagePack::RPC::Server.new(loop)
rpc.listen('127.0.0.1', 18800, RPCServer.new)

# イベントループを開始
loop.run

このプログラムを起動しておけば、他のアプリケーションからブラウザにプッシュ配信ができるという仕組みです。


実際に動くサンプルコードが frsyuki's rev-websocket at github に入っています。
他のサンプルと併せてチェックしてみてください。

*1:両方ともRevを使っているため、Rev-WebSocket と MessagePack-RPC サーバの両方を同じI/Oループに乗せることができます。

WebSocketサーバライブラリ rev-websocket リリース

いま WebSocket がにわかに注目を集めているようです。
ブラウザとサーバの間でリアルタイムな双方向通信を実現する機能で、HTML5に追加された(される予定の)新しい仕様です。
このWebSocketを使うには、ブラウザ側のJavaScriptの記述だけでなく、サーバ側の実装も必要になります。


そこで、Rubyで使えるWebSocketのサーバライブラリ rev-websocket をリリースしました。
gemでインストールできます:gem install rev-websocket


早速、デモアプリケーションを作ってみました:シャウッたー *1
http://visys.podzone.net:8080/


WebSocket を使ったチャットシステムに、ちょっとした演出を加えたシンプルなアプリケーションです。速くタイプするほど大きく表示されるという趣向です^^;
WebSocket に対応しているブラウザは今のところ SafariChromeFirefox 4 beta 1 ですが、他のブラウザでも Flash と JavaScript でエミュレーションしてくれるライブラリを使って動作します。感謝。(web_socket.js - HTML5のWeb SocketをFlashを使って実装


WebSocketはサーバとブラウザの間でコネクションを張りっぱなしにするため、いわゆるC10K問題に対処する必要があります。
rev-websocketは、高速なイベント駆動I/Oライブラリの Rev をベースにしており、大量のクライアントを効率よく扱うことができます。(参考:並列1000コネクションに耐える! Ruby のイベント駆動ライブラリ Rev と EventMachine の HTTPクライアント
プロトコルの処理には、Thin でも利用されている高速なプロトコルパーサを採用しています。
WebSocket はまだまだ仕様が安定していませんが、rev-websocketはドラフト75とドラフト76の両方に対応しています。


サーバ側のコードは↓こんな感じになります:

require 'rubygems'
require 'rev/websocket'    # gem install rev-websocket

# Rev::WebSocketを継承したクラスを作成
class MyConnection < Rev::WebSocket
  # 接続されたら呼ばれる
  def on_open
    puts "WebSocket opened"
    send_message("Hello, world!")  # メッセージを送る
  end

  # メッセージが届いたら呼ばれる
  def on_message(data)
    puts "WebSocket data received: '#{data}'"
    send_message("echo: #{data}")
  end

  # 切断されたら呼ばれる
  def on_close
    puts "WebSocket closed"
  end
end

server = Rev::WebSocketServer.new('0.0.0.0', 8080, MyConnection)
server.attach(Rev::Loop.default)

Rev::Loop.default.run


クライアント側のコードは、普通のWebSocketのプログラムと同じです。
ソースコードの中にある各種examplesや、シャウッたーのソースを覗いてみてください^^;

*1:期間限定公開です。そのうちに無くなります。。。

『Amebaなう』リアルタイム検索機能に Apache Solr と MessagePack を採用

ミニブログサービス「Amebaなう」に検索機能を追加 Apache Solrのカスタマイズにより検索パフォーマンスが大幅向上

検索機能は、当社の研究開発組織「インキュベーションラボラトリー」が開発し、Apache Solrをベースに、検索インデックス作成アルゴリズムの効率化や、データを高速かつ効率的に保存できる技術仕様「MessagePack」と各種圧縮アルゴリズムを組み合わせる等の対応を行いました。

あわせて読みたいLuceneのインデックスにStoreするデータをMessagePackで圧縮してみた - 社内NEET宣言


MessagePack と各種圧縮アルゴリズムを組み合わせることで、インデックスサイズを80%程度に圧縮することが可能になったようです。

MessagePack を使うと、配列やMapなどの構造を、非常にコンパクトに保存することができます。例えば、[1,2,3]という3つの整数からなる配列はたったの4バイト{"a":null}という連想配列はたったの4バイトで保存することが可能です。もしこれが JSON だと、それぞれ7バイトと10バイトも必要になります。

さらに Deflate などで圧縮すれば、非常に高い圧縮率が得られるという寸法です。先のjust_do_neetさんのブログによれば、作成速度も検索速度も、それほど速度劣化は起こっていないようです。


他に MessagePack を使ってデータサイズを圧縮している事例には、Data::Modelがあります。

KVSに保存するデータのスキーマをあらかじめ定義しておき、キー名を整数に変換するなどの変換を施すことで、空間効率を飛躍的に高めています:

例えば、上記のコードを使った場合に以下のようなデータ構造だった場合に


{
file_id => 'dankogai',
media_type => 1,
client_type => 5,
is_broken => undef,
},

Key を任意の値に変換してから直列化をかけます。
Data::Model 標準のシリアライザの MessagePack では、数値をとても効率よく直列化してくれるので、 media_type だとかいう長ったらしい key name を 2 とか言う数値に変換してしまいます。
2 とかという小さい値だと直列化後も1バイトしか容量食わなくて嬉しいんです!

実際、上のほうで書いてるデータ例だと以下の用になります。


{
2 => 1,
3 => 5,
},

これを MessagePack でシリアライズすると、元のデータは5バイトという驚異的なサイズとなって kumofs の value に格納されます。
memcachedにデータを保存する場合でも、このように空間効率を高めることで、キャッシュ可能なデータ量を増やすことができます:Data::Model::Driver::Memcachedで超効率データ保存


このように MessagePack は、速いだけでなく「小さい」という利点があります。MessagePack は JSON と型システムが同じ*1なので、JSON を使うところを単に MessagePack を使うようにするだけで、キャッシュのヒット率を向上させられたり、トラフィック量やCPU使用率を減らせるかもしれません。


それでは、MessagePack を使ったプログラミングをお楽しみください^^;

*1:整数、浮動小数点数、文字列、配列、連想配列、nil。JSON との互換性が高い点は MessagePack の大きな利点です。他のシリアライズ形式、例えば Protocol Buffers には配列配列型や連想配列がなく、Avro は値の型が異なる連想配列({a:["string",10], b:20, ...} のような)を扱えません。

進化するMessagePackプロジェクト - Webサイトリニューアル

MessagePack Project のWebサイトをリニューアルしました!
新しいURLは、http://msgpack.org/ です。


http://msgpack.org/


シンプルなイメージから若干趣を変え、完成度が高くてリッチな印象を重視しました ;-)
文章ではシリアライズの速度に加えて、RPCの意欲的な設計を強調しています。
なお、Twitterのハッシュタグは #msgpack です。ぜひツイートしてください^^;


実は先日、MessagePackプロジェクトについて StumbleUpon の研究開発チームの方々にプレゼンテーションしてきました。(参考:FacebookとStumbleUponの方がTwitterよりトラフィックを生んでいる
写真を一枚^^;
http://d.hatena.ne.jp/viver/20100620/p1


さらに、LuceneHadoop開発者であり、Avroの開発者でもある Doug Cutting 氏(Wikipedia!)ともディスカッションする機会がありました!
http://d.hatena.ne.jp/viver/20100620/p1


そのときのスライドは、SlideShareにアップロードしています。MessagePackプロジェクトは、いま着々と進化しています。
Architecture of MessagePack - SlideShare


トップページの比較表やMessagePack-RPC Designを読むと分かりますが、MessagePack-RPCは、FacebookからリリースされたThriftや、Hadoopのサブプロジェクトとして進行しているAvroと比べても、まったく遜色ないどころか、ずっと優れた設計を既に有しています。

http://msgpack.org/


MessagePack-RPCのもっとも大きな特徴は、スクリプト言語で書かれたフロントエンドとJavaC++で書かれたバックエンドの間で通信したい場合など、異なる言語間での通信を実現する点です。それぞれのモジュールを実装するために適切な言語を選択して、分散システム全体を構築していくことができます。
しかし、それだけではありません。非同期通信通信の並列・パイプライン化など、昨今では当然のように必要になる機能でありながら、ThriftやAvroでは実現できなかった、先進的な機能をサポートしています。


http://redmine.msgpack.org/projects/msgpack/wiki/RPCDesign#ParallelPipelining


新しいWikiでは、MessagePackの詳しい設計とメリットについて述べています:

これらのドキュメントは Preferred Infrastructure, Inc. のkzkさんによって書かれました。(MessagePack は Preferred Infrastructure 社の製品である Sedue採用されています
新しいWikiには、開発者のクレジットのページがあります。HadoopのWikiなどにもあるアレです。イカしたコードやドキュメントをコミットすると、きっと名前が載ります!


MessagePackのメーリングリストも新しくなりました。
MessagePackへの質問などと同時に、今開発しているこんなシステムで使いたいーといった利用事例なども同時に流れてくるかもしれません。この機会にぜひご参加ください^^;




Subscribe to MessagePack

Email:


Visit this group


こちらは開発者向けのメーリングリストです。他の言語に移植したい!という計画がある方は、ここで名乗りを上げると良いでしょう;-)




Subscribe to MessagePack Developers

Email:


Visit this group

IRCチャンネルもあります。たまに議論が巻き起こります。英語です^^;
チャンネル名は#msgpackで、irc.freenode.netにあります。


徐々に利用事例も増えてきました。Amebaなう でも採用されたようです。(Powred by MessagePack
MessagePackは、今がいちばん「旬」のプロジェクトかもしれません。


MessagePackで相互に繋がるエコ・システムを夢見ていたりするのですが、シリアライズ/RPCより少し高めのレイヤーのアプリケーションにも着手していきたいと思っているところです。