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より少し高めのレイヤーのアプリケーションにも着手していきたいと思っているところです。

シリコンバレーにいます

6月5日から6月27日までの約3週間の間、サンフランシスコ・マウンテンビューの周辺に滞在しています。
実は日本国外に脱出したのは今回が初めてで、飛行機に乗る段階から驚きの連続です^^;



滞在先のホテルから撮影した風景。眼前にはサンフランシスコの町並みと、見渡す限りの青空が広がっています。



初日にフィッシャーマンズ・ワーフで食べたお昼ご飯の光景。眼前には「カラマリ」なるイカのフライと、大量のポテトが広がっています。



サンフランシスコの朝は霧が濃い。



ダウンタウン・マウンテンビュー駅。道が広い。空が広い。空気はカラっと乾いて快適。そして町中で Google Wi-Fi が使える。快適な町 Mountain View。


これまでに、Cloudera社のDoug Cutting氏や、StumbleUpon社の研究開発チームとディスカッションする機会がありました。


ちなみにStumbleUpon社は、Twitterで「いまSan Franciscoにいる」とつぶやいたところ、「ちょっと会わないか」と声をかけられました(笑)

もし現地で活動している方がいらっしゃいましたら、メールやTwitter@frsyuki, @frsyuki_ha)までお声がけください。ぜひkumofsやMessagePackプロジェクトの広報に伺いたいと思います^^;(特に現在、MessagePackをプロダクトに組み込むお話を探しています)


kumofsMessagePackプロジェクトについて、英語版のプレゼンテーション資料を公開しました。

MessagePackはコミッタの方々の共同作業によって、現在飛ぶ鳥を落とす勢い完成度が向上しています。
新しいWebサイトも準備中です。ぜひご期待ください^^;

kumofsのメーリングリストができました

できました。興味のある方はぜひご参加ください^^;


Google グループ
kumofs-jaに参加
メール:

このグループにアクセス


kumofsのウェブサイトも更新しています。管理とチューニングの項目を追加しました。
The Kumofs Project

英語版

英語のメーリングリストもあります。お気軽にどうぞ。


Google Groups

Subscribe to kumofs

Email:


Visit this group

経緯

kumofsってML的なコミュニティは無しでtwitterだけで行くのかな?途中からはじめようと思った人が状況を追えたりするようなモノはあったほうがいいかなというのが昨日、話題になった。
http://twitter.com/masahif2/status/14430791031

@frsyuki オープンソースのプロダクツは、開発体制やコミュニティの存在が選択に当たっては重要だよねって話をしてました。
http://twitter.com/masahif2/status/14430956007

kumofsのメーリングリストができました。興味のある方はぜひご参加ください^^; http://groups.google.com/group/kumofs-ja
http://twitter.com/frsyuki/status/14431191568