最近見つけたMessagePack、代替 Googleの Protocol Buffers および JSON へのbinaryシリアル化形式は、どちらも優れています。
また、データを保存するためにMongoDBで使用される BSON シリアル化形式もあります。
BSONとMessagePackの違いと欠点/利点を詳しく説明できますか?
高性能なバイナリシリアル化形式のリストを完成させるためだけに、次もあります。 Gobs googleのProtocol Buffersの後継になる。しかしながら 言及されている他のすべての形式とは対照的に、これらは言語に依存せず、 Goの組み込みリフレクション に依存しています 少なくともGo以外の言語用のGobsライブラリもあります。
//私はMessagePackの作成者であることに注意してください。この答えには偏りがあるかもしれません。
フォーマット設計
JSONとの互換性
その名前にもかかわらず、BSONのJSONとの互換性は、MessagePackと比較してそれほど良くありません。
BSONには、「ObjectId」、「Min key」、「UUID」、「MD5」などの特別なタイプがあります(これらのタイプはMongoDBで必要だと思います)。これらのタイプはJSONと互換性がありません。つまり、オブジェクトをBSONからJSONに変換すると、一部のタイプ情報が失われる可能性がありますが、もちろんこれらの特別なタイプがBSONソースにある場合のみです。単一のサービスでJSONとBSONの両方を使用することは不利な場合があります。
MessagePackは、JSONとの間で透過的に変換されるように設計されています。
MessagePackはBSONよりも小さい
MessagePackの形式は、BSONより冗長ではありません。その結果、MessagePackはBSONよりも小さいオブジェクトをシリアル化できます。
たとえば、単純なマップ{"a":1、 "b":2}はMessagePackで7バイトにシリアル化されますが、BSONは19バイトを使用します。
BSONはインプレース更新をサポートします
BSONを使用すると、オブジェクト全体を再シリアル化することなく、保存されているオブジェクトの一部を変更できます。マップ{"a":1、 "b":2}がファイルに保存されていて、 "a"の値を1から2000に更新するとします。
MessagePackでは、1は1バイトのみを使用しますが、2000は3バイトを使用します。したがって、「b」は2バイトだけ後方に移動する必要がありますが、「b」は変更されません。
BSONでは、1と2000の両方が5バイトを使用します。この冗長性のため、「b」を移動する必要はありません。
MessagePackにはRPCがあります
MessagePack、Protocol Buffers、Thrift、AvroはRPCをサポートしています。しかし、BSONはそうではありません。
これらの違いは、MessagePackが元々ネットワーク通信用に設計されているのに対し、BSONはストレージ用に設計されていることを意味します。
実装とAPI設計
MessagePackには型チェックAPI(Java、C++、およびD)があります
MessagePackは静的型付けをサポートしています。
JSONまたはBSONで使用される動的型指定は、Ruby、Python、またはJavaScriptなどの動的言語に役立ちます。しかし、静的言語にとっては面倒です。退屈なタイプチェックコードを記述する必要があります。
MessagePackは、型チェックAPIを提供します。動的に型付けされたオブジェクトを静的に型付けされたオブジェクトに変換します。以下に簡単な例を示します(C++):
#include <msgpack.hpp>
class myclass {
private:
std::string str;
std::vector<int> vec;
public:
// This macro enables this class to be serialized/deserialized
MSGPACK_DEFINE(str, vec);
};
int main(void) {
// serialize
myclass m1 = ...;
msgpack::sbuffer buffer;
msgpack::pack(&buffer, m1);
// deserialize
msgpack::unpacked result;
msgpack::unpack(&result, buffer.data(), buffer.size());
// you get dynamically-typed object
msgpack::object obj = result.get();
// convert it to statically-typed object
myclass m2 = obj.as<myclass>();
}
MessagePackにはIDLがあります
これは型チェックAPIに関連しており、MessagePackはIDLをサポートしています。 (仕様は以下から入手できます: http://wiki.msgpack.org/display/MSGPACK/Design+of+IDL )
プロトコルバッファとスリフトはIDLを必要とし(ダイナミックタイピングをサポートしない)、より成熟したIDL実装を提供します。
MessagePackにはストリーミングAPI(Ruby、Python、Java、C++など)があります
MessagePackは、ストリーミングデシリアライザーをサポートしています。この機能は、ネットワーク通信に役立ちます。次に例を示します(Ruby):
require 'msgpack'
# write objects to stdout
$stdout.write [1,2,3].to_msgpack
$stdout.write [1,2,3].to_msgpack
# read objects from stdin using streaming deserializer
unpacker = MessagePack::Unpacker.new($stdin)
# use iterator
unpacker.each {|obj|
p obj
}
私はこの質問がこの時点で少し時代遅れであることを知っています...それはあなたのクライアント/サーバー環境がどのように見えるかに依存することに言及することは非常に重要だと思います。
メッセージキューシステムやディスクへのログエントリのストリーミングなど、検査せずにバイトを複数回渡す場合は、コンパクトサイズを強調するためにバイナリエンコーディングを使用することをお勧めします。それ以外の場合は、異なる環境でのケースバイケースの問題です。
環境によっては、msgpack/protobufとの間で非常に高速なシリアル化と逆シリアル化が可能な場合とそうでない場合があります。一般的に、言語/環境が低レベルであるほど、バイナリシリアル化が機能します。高レベルの言語(node.js、.Net、JVM)では、JSONシリアル化が実際に高速であることがよくわかります。問題は、メモリ/ CPUよりもネットワークオーバーヘッドが多少制約されているかどうかです。
Msgpack vs bson vs protocol buffersに関して... msgpackはグループの最小バイトで、プロトコルバッファはほぼ同じです。 BSONは、他の2つよりも幅広いネイティブタイプを定義し、オブジェクトモードにより適している場合がありますが、これにより、より冗長になります。プロトコルバッファには、ストリーミングするように設計されているという利点があります。これにより、バイナリ転送/ストレージ形式のより自然な形式になります。
個人的には、より軽いトラフィックが明確に必要でない限り、JSONが直接提供する透明性に傾倒します。 gzip圧縮されたデータを使用したHTTPを介した場合、ネットワークオーバーヘッドの違いは、フォーマット間で問題がさらに少なくなります。
クイックテストは、縮小されたJSONがバイナリMessagePackよりも高速にデシリアライズされることを示しています。テストでは、Article.jsonは550kbの縮小JSONであり、Article.mpackは420kb MPバージョンです。もちろん実装の問題かもしれません。
メッセージパック:
//test_mp.js
var msg = require('msgpack');
var fs = require('fs');
var article = fs.readFileSync('Article.mpack');
for (var i = 0; i < 10000; i++) {
msg.unpack(article);
}
JSON:
// test_json.js
var msg = require('msgpack');
var fs = require('fs');
var article = fs.readFileSync('Article.json', 'utf-8');
for (var i = 0; i < 10000; i++) {
JSON.parse(article);
}
時代は次のとおりです。
Anarki:Downloads oleksii$ time node test_mp.js
real 2m45.042s
user 2m44.662s
sys 0m2.034s
Anarki:Downloads oleksii$ time node test_json.js
real 2m15.497s
user 2m15.458s
sys 0m0.824s
スペースは節約できますが、高速ですか?番号。
テスト済みのバージョン:
Anarki:Downloads oleksii$ node --version
v0.8.12
Anarki:Downloads oleksii$ npm list msgpack
/Users/oleksii
└── [email protected]
MessagePackとBSONのエンコードとデコードの速度を比較するための簡単なベンチマークを作成しました。 BSONは、少なくとも大きなバイナリ配列がある場合は高速です。
BSON writer: 2296 ms (243487 bytes)
BSON reader: 435 ms
MESSAGEPACK writer: 5472 ms (243510 bytes)
MESSAGEPACK reader: 1364 ms
NeueccによるC#Newtonsoft.JsonおよびMessagePackの使用:
public class TestData
{
public byte[] buffer;
public bool foobar;
public int x, y, w, h;
}
static void Main(string[] args)
{
try
{
int loop = 10000;
var buffer = new TestData();
TestData data2;
byte[] data = null;
int val = 0, val2 = 0, val3 = 0;
buffer.buffer = new byte[243432];
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < loop; i++)
{
data = SerializeBson(buffer);
val2 = data.Length;
}
var rc1 = sw.ElapsedMilliseconds;
sw.Restart();
for (int i = 0; i < loop; i++)
{
data2 = DeserializeBson(data);
val += data2.buffer[0];
}
var rc2 = sw.ElapsedMilliseconds;
sw.Restart();
for (int i = 0; i < loop; i++)
{
data = SerializeMP(buffer);
val3 = data.Length;
val += data[0];
}
var rc3 = sw.ElapsedMilliseconds;
sw.Restart();
for (int i = 0; i < loop; i++)
{
data2 = DeserializeMP(data);
val += data2.buffer[0];
}
var rc4 = sw.ElapsedMilliseconds;
Console.WriteLine("Results:", val);
Console.WriteLine("BSON writer: {0} ms ({1} bytes)", rc1, val2);
Console.WriteLine("BSON reader: {0} ms", rc2);
Console.WriteLine("MESSAGEPACK writer: {0} ms ({1} bytes)", rc3, val3);
Console.WriteLine("MESSAGEPACK reader: {0} ms", rc4);
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadLine();
}
static private byte[] SerializeBson(TestData data)
{
var ms = new MemoryStream();
using (var writer = new Newtonsoft.Json.Bson.BsonWriter(ms))
{
var s = new Newtonsoft.Json.JsonSerializer();
s.Serialize(writer, data);
return ms.ToArray();
}
}
static private TestData DeserializeBson(byte[] data)
{
var ms = new MemoryStream(data);
using (var reader = new Newtonsoft.Json.Bson.BsonReader(ms))
{
var s = new Newtonsoft.Json.JsonSerializer();
return s.Deserialize<TestData>(reader);
}
}
static private byte[] SerializeMP(TestData data)
{
return MessagePackSerializer.Typeless.Serialize(data);
}
static private TestData DeserializeMP(byte[] data)
{
return (TestData)MessagePackSerializer.Typeless.Deserialize(data);
}
まだ言及されていない重要な違いは、BSONにはドキュメント全体およびさらにネストされたサブドキュメントのサイズ情報がバイト単位で含まれていることです。
document ::= int32 e_list
これには、サイズとパフォーマンスが重要な制限された環境(組み込みなど)に2つの大きな利点があります。