• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content

Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

Programming Tools and Techniques #369 - The MessagePack Project

on

  • 2,038 views

 

Statistics

Views

Total Views
2,038
Views on SlideShare
2,038
Embed Views
0

Actions

Likes
2
Downloads
10
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Programming Tools and Techniques #369 - The MessagePack Project Programming Tools and Techniques #369 - The MessagePack Project Presentation Transcript

    • TheMessagePackProjectProgramming Tools and Techniques第369回古橋 貞 之#msgpack @frsyukihttp://d.hatena.ne.jp/viver/
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • 背景• 多言語でシステムを構築したい > C++で分散KVSを実装 + Rubyで管理を自動化 > Rubyでプロトタイプ → 段階的にC++に移植 > Javaサーバ + Rubyクライアント• スケールアウト時代に耐える通信システムが欲しい > 多数のサーバやクライアントが並列して通信 > マルチコア環境でもスケールする並列性
    • 理想 C++ 高速で多機能で使いやすい オープンソースのライブラリ Interface Interface Interface Java Ruby各言語の利点を活かして 通信のパイプライン化や並列化などの本質的な設計に集中 高速化手法をシンプルに使える
    • 従来のRPC• Java-RMI• XML-RPC, SOAP• JSON-RPC• SunRPC• Protocol Buffers:GoogleのRPC/シリアライザ• Avro:HadoopのRPC/シリアライザ• Thrift:FacebookのRPC/シリアライザ
    • 従来のシリアライザ• Java Serializable• XML• JSON• XDR• Protocol Buffers:GoogleのRPC/シリアライザ• Avro:HadoopのRPC/シリアライザ• Thrift:FacebookのRPC/シリアライザ
    • 従来の問題• 多言語対応自体の実装が面倒で、本質的な機能の 実装に集中できない• オーバーヘッドの大きいプログラムができあがる > リソースの消費量が増え、サーバの台数が増える• 並列化や非同期化が難しく、高負荷に対応しにくい > 自前実装はバグの元 =「高負荷になると固まる」 > ネットワーク/マルチスレッド/イベント駆動には罠が多い
    • 従来の問題2• プロトコルを後から(無停止で)更新したい > サーバの一部を最新版に更新 > ↑繰り返して無停止で全サーバを更新 ローリングアップデート
    • MessagePackによる解決• 高速で多機能で多言語対応した通信システムを提供 > 本質的な機能の実装に集中できる > 用途に合った言語を選択できる > プロトタイピング→別の言語で本番実装 も容易• データサイズやCPU負荷を削減して、サーバの台 数を減らす• 互換性を保ったままプロトコルを拡張可能• 複数のサーバと並列して通信できる
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • シリアライザ• シリアライザの役割 > オブジェクトをバイト列に変換 > バイト列からオブジェクトを復元• シリアライザの用途 > オブジェクトをDBやキャッシュに保存 > オブジェクトをネットワーク越しに転送
    • require msgpack # gem install “msgpack"raw = [1,2,3].to_msgpack #=> "x93x01x02x03"MessagePack.unpack(raw) #=> [1,2,3] Rubypublic class Main { public static void main(String[] args) { byte[] raw = MessagePack.pack(new MyClass()); MyClass dst = MessagePack.unpack(raw, MyClass.class); }} Javaint main() { msgpack::sbuffer raw; std::vector<int> src; std::vector<int> dst; msgpack::pack(raw, src); msgpack::unpack(raw.data(), raw.size())->convert(&dst);} C++
    • シリアライザの選択• 多言語対応 > 特定の言語と密結合化するか、疎結合化するか• データ型の扱い方• フォーマットの設計• プログラムの更新 <-> データの互換性• ストリーミング対応
    • 多言語対応要求:異種言語間の型システムの差異を吸収 例:配列と連想配列の区別がない, クラスが無い手法: MessagePackの型システム を導入 各言語に MessagePackの型 と 言語の型 の相互に変換す る機能を実装。特定の言語に密結合しない補足:JSONの型システムをそのまま採用 使いやすさが実証された型システム MessagePackとJSONとの相互変換も可能になる
    • 多言語対応C++の型 Javaの型 Rubyの型 相互変換 MessagePackの型
    • 多言語対応論理構造 言語の型 変換 MessagePackの型 ライブラリで 提供 変換 データ
    • 多言語対応 論理構造 言語の型 変換 互換MessagePackの型 JSONの型 変換 データ
    • 多言語対応• MessagePackの型システム=仲介用の型システム > 言語の型と相互に変換する機能を提供• JSONと同じ型システム > JSONに変換して表示したりできる > Webサービスと連携しやすい• シンプルな型だけをサポート > 標準化が難しい型はアプリケーションで対処 > 例:日付型や正規表現型はサポートしない
    • 使い勝手の問題要求:型定義ファイルを書くのが面倒 例:XDR 定義ファイルが無いとデータを読めない→保守性の悪さも要求:型検査(型変換)をして欲しい XMLを自分で解析するのは面倒だし、バグが入りやすい XMLスキーマは、それ自体の記述が面倒手法:データに型情報を埋め込む手法: 型変換テンプレート を導入 コードの中で型情報を記述
    • 型定義ファイル バイト列 型定義ファイル message Person {   string name = 1;   int32 id = 2;   string email = 3;   PhoneNumber phone = 4; } 例: XDR, Protocol Buffers,オブジェクト Thrift など
    • 型定義ファイルの問題 バイト列 型定義ファイル 記述が面倒 常に最新の定義ファイル  を配布する手間 ゴミ! データをキャプチャして  デバッグ ができないオブジェクト ○ 型検査が効く
    • 型情報の埋め込み バイト列 型情報を埋め込んでおく 例: JSON, MessagePackなど デシリアライズ ○ すぐに使えて便利 可能 型検査が効かない?オブジェクト  (動的な型付け)
    • テンプレート バイト列 テンプレート 言語の中に記述 型検査オブジェクト
    • #include <msgpack.hpp> C++int main() { std::vector<std::string> src; src.push_back("msgpack"); src.push_back("kumofs"); msgpack::sbuffer out; msgpack::pack(out, src); msgpack::unpacked result; msgpack::unpack(&result, out.data(), out.size()); msgpack::object data = result.get(); // テンプレートによる型検査 + 型変換 data.as< std::vector<std::string> >();}
    • import org.msgpack.MessagePack; Javaimport org.msgpack.Templates.*;public class Main { public static void main(String[] args) { byte[] raw = MessagePack.pack(...); // テンプレートによる型検査 + 型変換 MessagePackObject dynamic = MessagePack.unpack(raw); List<String> dst1 = (List<String>) dynamic.convert( tList(TString) ); // Direct conversion List<String> dst2 = MessagePack.unpack(raw, tList(TString) ); }}
    • フォーマット要求:データサイズを削減したい キャッシュサーバでは、データが小さいほどキャッシュ ヒット率が上がる 検索サーバでは、データが小さいほどインデックスがメモ リに載りやすくなり、HDDのシーク回数を削減できる手法:よく使うデータほど小さく保存 1つの型につき複数の保存形式を用意、最小の形式を選択手法:型情報と値をくっつけて1バイトにする
    • フォーマット非コンテナ型 コンテナ型 type value type length body... body...type + value type + length よく使う(小さいデータ)は、 型情報+値/長さ を1バイトで保存
    • Type information Type information Types 0x00 nil 0xc2 false 0xc3 true 0xca float 0xcb double 0xcc uint8 0xcd uint160xc0 0xce uint320xe0 0xcf uint64 0xdf int8 ... ...
    • Type information Type information Types0x00 0x00 nil 0xc2 false 0xc3 true Positive FixNum 0xca float 0xcb double0x80 FixMap 0xcc uint80x900xa0 FixArray 0xcd uint160xc0 FixRaw 0xce uint320xe0 0xcf uint64 Negative FixNum 0xdf int8 ... ...
    • JSONとの比較 JSON MessagePack null null c0Integer 10 0aArray [20] 91 14String “30” a2 ‘3’ ‘0’ Map {“40”:null} 81 a2 ‘4’ ‘0’ c0
    • JSONとの比較 JSON MessagePack null null 4 bytes c0 1 byteInteger 10 2 bytes 0a 1 byteArray [20] 4 bytes 91 14 2 bytesString “30” 4 bytes a2 ‘3’ ‘0’ bytes 3 Map {“40”:null}bytes 11 5 bytes 81 a2 ‘4’ ‘0’ c0
    • JSONとの比較 {“msgpack”:“json”, “hello”:“world”} JSON MessagePack 34 bytes 26 bytes 24%削減別の事例:ある日のTwitterのpublic_timeline:JSON 31KB => MessagePack 25KB(19%削減)
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • 互換性の問題要求:古いデータが読めなくなると困る データの寿命は、プログラムの更新間隔より長い手法: optionalフィールド を導入 フィールドの省略を許す;新しいフィールドが入っていな い古いデータを受け入れる 余分なフィールドは単に無視する;古いアプリケーション が新しいデータを読むこともできる手法:アノテーションで記述(Java版)
    • Optionalフィールド@MessagePackMessagepublic static class MyClass { public String str; public double num;}
    • Optionalフィールド@MessagePackMessagepublic static class MyClass { public String str; public double num; @Optional public int flag = 0;}
    • 高速化Direct conversion 中間の型システムを経由せずに、特定の型に直接デシリア ライズする。D版で提唱、Java版に実装、C++版に実装中動的コード生成 型変換コードを実行時に生成・コンパイルして最適化す る。Java版に実装。ストリームデシリアライザ ストリームからのデシリアライズを効率よく実装。 C++版では ゼロコピー化 も導入
    • 多言語対応 Direct conversion 言語の型 変換 MessagePackの型 変換 データDirect conversion
    • ストリーミングrequire msgpacku = MessagePack::Unpacker.new($stdin)u.each do |obj| puts obj.to_jsonend
    • Zero-copy deserialization
    • Zero-copy deserialization It measured the elapsed time of serializing and deserializing 200,000 target objects. The target object consists of the three integers and 512 bytes string.
    • msgpack json protobuf avro thrift 形式 binary text binary binary binary 外部型情報 埋め込み 埋め込み 外部 (添付) 外部 コード内に記述 必須 必須 必須 JSONスキーマ記述 Thrift互換形式の IDLも実装中 Schema? (独自DSL) (JSON形式) (独自DSL)ストリーミング 対応 できるはず 非対応 非対応 非対応 RPC msgpack-rpc json-rpc (非公開) avro thriftシリアライザ単体で利用 可能 可能 可能 可能 面倒
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • require msgpack/rpcclass MyHandler def add(x,y) return x+y endendsvr = MessagePack::RPC::Server.newsvr.listen(0.0.0.0, 18800, MyHandler.new)svr.runrequire msgpack/rpcc = MessagePack::RPC::Client.new(127.0.0.1, 18800)result = c.call(:add, 1, 2) #=> 3
    • public class MyService { public void set(String key, String value) { // ... } public String get(String key) { return "..."; } public static void main(String[] args) { Server svr = new Server(); svr.serve(new DynamicDispatcher( new MyService()) ); svr.listen(9090); svr.getEventLoop().getExecutor() .awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); }}
    • MessagePack-RPC要求:多数のクライアントと効率よく通信 C10K問題;イベント駆動I/Oが必要要求:複数のホストと同時に通信したい 多数のサーバが連携する分散システムが台頭要求:通信を計算とオーバーラップさせて、   通信の遅延を隠蔽したい 非同期呼び出し
    • MessagePack-RPC要求:マルチコア環境でスケールして欲しい要求:マルチスレッドなコードは書きたくない 自分でスレッドを立てたり同期したりするコードは面倒だ し、バグの元になる要求:イベント駆動なコードも書きたくない要求: TCPコネクション を意識したくない 耐障害性の高いプログラムを書くには、再接続が必須 高負荷に耐えるプログラムを書くには、接続維持が必須
    • MessagePack-RPC手法:処理順を入れ替えられるプロトコル サーバ側で並列化が容易 要求はすべて並列して処理し、早く終わったらすぐに返す手法:イベント駆動I/O(サーバ側) よくあるアーキテクチャ;リソースの消費量を削減手法:イベント駆動I/O(クライアント側) 複数の サーバ と並列して通信できる マルチスレッド化が不要
    • MessagePack-RPC手法: Future 非同期I/Oを隠蔽;コードを簡略化する 並列化できるI/Oは勝手に並列化する手法: Session コネクションの概念を隠蔽;コードを簡略化する コネクションの確立・維持・再接続を自動的に行う
    • プロトコル JSON-RPCをベースにしたプロトコル設計Request[0, msgid, method, params] メッセージIDResponse →Parallel Pipelining[1, msgid, error, result]Notify[2, method, params]
    • 並列性クライアント サーバ パイプライン化 応答が帰ってくる前に立て続け に複数の要求を発行することで 高速化を図る 実装例: ・HTTP/1.1 pipelining ・Thrift ・SOAP
    • 並列性クライアント サーバ 重いタスクが軽いタスクを待たせる > 並列性が低下 重いタスク 軽いタスク 順番を揃える 実装例: (キュー) ・HTTP/1.1 pipelining ・Thrift ・SOAP
    • Parallel Pipelining 応答の順番を揃える必要が無いクライアント サーバ 早く終わったタスクはすぐに返す > 並列性が向上 > サーバのリソース消費量を削減 重いタスク 軽いタスク 実装例: ・MessagePack-RPC 時間短縮
    • イベント駆動I/Oサーバーサイド イベント駆動I/O大量のクライアントと効率的に通信できる Client Server Dispatcher Loopmulti-threaded event-driven I/O Client (C++, Java)
    • イベント駆動I/Oクライアントサイド イベント駆動I/O Client Session Loop Server Client Session Loop Server
    • イベント駆動I/Oクライアントサイド イベント駆動I/O Client Session Server Loop 並列して通信可能 Client shared Session event loop Server
    • イベント駆動I/Oクライアントサイド イベント駆動I/O connection Session Server Session Pool pools these Loop connections Session Server
    • イベント駆動I/Oクライアントサイド イベント駆動I/O Client サーバとクライアントを同じ イベントループ上で動作 Session ServerDispatcher Loop Client shared Session event loop Server
    • イベント駆動I/Oクライアントサイド イベント駆動I/O Client サーバとクライアントを同じ イベントループ上で動作 Session Server Dispatcher Loop Client sharedtimer, signal handler, event loopother protocol, etc...
    • Future 非同期処理を抽象化require msgpack/rpcloop = MessagePack::RPC::Loop.newc1 = MessagePack::RPC::Client.new(host, port, loop)c2 = MessagePack::RPC::Client.new(host, port, loop)future1 = c1.call_async(:method1, arg)future2 = c2.call_async(:method2, arg)future2.getfuture1.get
    • セッションコネクションの隠蔽 非同期処理を抽象化 コネクションを隠蔽Future connection Session ServerFuture LoopFuture shared Session event loop ServerFuture
    • セッションコネクションの隠蔽 非同期処理を抽象化 コネクションを隠蔽 セッション:Future コネクションを直接制御させない Session > 接続が切れたら自動的に再接続Future > コネクションプーリング Future:Future 非同期処理を直接記述させない > 記述を簡略化Future Session > バックグラウンドで処理できる 通信は自動的に並列処理
    • MessagePack-RPC• 応答を順不同で返せるプロトコル > 並列化が容易;すべてのRPC要求を並列処理• クライアント側もイベント駆動 > 多数のサーバと効率よく通信できる• 多数のサーバが連携する分散システムをシンプルに 実装可能 > 明示的なマルチスレッド化やイベント駆動I/Oの プログラミングは不要
    • MessagePack-RPC• コネクションプーリング > 1本のコネクションを複数スレッドで共有できる > オーバーヘッドを大幅に削減可能 > Sessionで隠蔽;自動的な再接続もサポート• サーバとクライアントのアーキテクチャが対称的 > 1つのイベントループに様々なイベントハンドラ を追加のせてプログラムを構築できる > サーバとクライアントの両方の特性を持つホスト
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • 事例• Sedue Search Cloud• Amebaなう• kumofs• Sekai Camera• mycached• Ficia• Cassandra?
    • Sedue Cloud Search: 簡単に使える高性能検索エンジン・レコメンドエンジンクラウドサービスhttp://sedue.sc/
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • 背景 > 従来の問題MessagePack - 高速シリアライザ > 多言語対応と型システム > フォーマット > 互換性の問題 > 高速化の手法MessagePack-RPC - 多機能RPC > プロトコルと Parallel Pipelining > 並列イベント駆動I/O > FutureとSessionによる隠蔽事例
    • まとめ - MessagePack• MessagePackの型システム > JSON互換• 型情報をデータに埋め込む; 定義ファイルが不要 > コンパクトに埋め込む• テンプレートによる型検査• optionalフィールド• ストリーミング機能• ゼロコピー
    • まとめ - MessagePack-RPC• Parallel Pipelining > 処理を並列化;早く終わったら早く返す• クライアントサイド イベント駆動I/O > 複数のサーバと並列して通信• Future• Session > コネクションの確立・維持・再接続を隠蔽/自動化
    • まとめ - The MessagePack Project• 世界で利用拡大中• コミッタ募集中• 利用事例募集中
    • MessagePack 対応言語と開発者の一部• C++ > Sadayuki Furuhashi • > Perl tokuhirom, gfx, ...• Ruby > Sadayuki Furuhashi • > Erlang UENISHI Kota• Java > Muga Nishizawa • > Node.JS Peter Griess• Python > INADA Naoki • > JavaScript uupaa• Haskell > Hideyuki Tanaka • > PHP advect• Lua > Nobuyuki Kubota • > D repeatedly
    • MessagePack-RPC 対応言語と開発者の一部• C++版 - Sadayuki Furuhashi• Erlang版 - UENISHI Kota• Haskell版 - Hideyuki Tanaka• Java版 - Muga Nishizawa• PHP版 - h0x10• Python版 - INADA Naoki• Ruby版 - Sadayuki Furuhashi
    • http://msgpack.org/ http://github.com/msgpackTwitter: #msgpack msgpack@googlegroups