2011-06-15 166 views
113

最近我发现MessagePack,替代二进制序列化格式,以谷歌的Protocol BuffersJSON也优于两者。高性能系列化实体:BSON VS MessagePack(VS JSON)

此外还有MongoDB用于存储数据的BSON序列化格式。

有人可以详细说明区别以及BSON与MessagePack的区别/优点


刚刚完成的高性能的二进制序列化格式列表:也有Gobs 这将是谷歌的协议缓冲 的继任者。然而, 与所有其他提及的格式不同,它们不是语言不可知的,并且依赖于 Go's built-in reflection ,至少在Go以外的语言中也有Gobs库。

+3

似乎主要是像市场炒作负荷。 [“编译”]序列化格式的性能是由于使用的实现。尽管某些格式本身具有更多开销(例如JSON,因为它全部是动态处理的),但格式本身并不“有速度”。然后页面继续“挑选”它如何比较自己......这是一种非公正的时尚。不是我喜欢的。 – 2011-06-15 09:20:53

+6

更正:Gobs无意取代Protocol Buffers,也可能永远不会。此外,Gobs是语言不可知的(它们可以用任何语言阅读/编写,请参阅http://code.google.com/p/libgob/),但它们被定义为与Go处理数据的方式非常匹配,因此它们可以工作与Go最好。 – 2011-06-15 18:59:23

+5

链接到msgpack性能基准测试失败(http://msgpack.org/index/speedtest.png)。 – 2012-10-04 21:12:23

回答

157

//请注意我是MessagePack的作者。这个答案可能是有偏见的。

格式设计

  1. 与JSON

    尽管它的名字的兼容性,与MessagePack相比BSON与JSON的兼容性也不是那么好。

    BSON有“ObjectId”,“Min key”,“UUID”或“MD5”(我认为MongoDB需要这些类型)的特殊类型。这些类型与JSON不兼容。这意味着某些类型信息在将对象从BSON转换为JSON时会丢失。在单一服务中使用JSON和BSON可能是不利的。

    MessagePack被设计为从/到JSON透明转换。

  2. MessagePack比BSON

    小MessagePack的格式比BSON更简洁。结果,MessagePack可以序列化小于BSON的对象。

    例如,一个简单的映射{“a”:1,“b”:2}被7个字节的MessagePack序列化,而BSON使用19个字节。

  3. BSON支持就地更新

    随着BSON,您可以修改存储对象的一部分,而无需重新整序列化对象。假设地图{“a”:1,“b”:2}存储在一个文件中,并且您希望将“a”的值从1更新为2000.

    使用MessagePack,1仅使用1个字节但2000年使用3个字节。所以“b”必须向后移动2个字节,而“b”没有被修改。

    使用BSON,1和2000都使用5个字节。由于这种冗长,你不必移动“b”。

  4. MessagePack具有RPC

    MessagePack,协议缓冲区,节俭和Avro的支持RPC。但是BSON没有。

这些差异意味着MessagePack最初设计用于网络通信,而BSON设计用于存储。

实施和API设计

  1. 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>(); 
    } 
    
  2. MessagePack具有IDL

    它相关的类型检查API,MessagePack支持IDL。 (规范可从:http://wiki.msgpack.org/display/MSGPACK/Design+of+IDL

    Protocol Buffers和Thrift需要IDL(不支持动态输入)并提供更成熟的IDL实现。

  3. MessagePack已经流API(红宝石,Python和Java和C++,...)

    MessagePack支持流解串器。该功能对网络通信非常有用。下面是一个例子(红宝石):

    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 
    } 
    
+25

MessagePack与Google Protobufs在数据大小方面以及空中性能方面的比较如何? – Ellis 2011-06-17 11:15:13

+2

第一点掩盖了MessagePack具有无法用JSON表示的原始字节能力的事实。所以它只是同BSON在这方面... – hplbsh 2011-09-02 02:40:33

+3

@lttlrck一般来说,原始字节被认为是一个字符串(通常是UTF-8),除非另有预期,并同意在通道的两侧。 msgpack被用作流/序列化格式...并且较少详细说明json ..虽然也较少用于人类可读。 – Tracker1 2012-08-08 22:16:28

4

快速测试显示缩小的JSON反序列化不是二进制MessagePack更快。在测试中,Article.json是550kb缩小的JSON,Article.mpack是它的420kb MP版本。当然可能是一个实现问题。

MessagePack:

//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] 
+5

绝对取决于实现。我使用Python 2.7.3对489K test.json(相当于409K test.msgpack)进行了测试,结果表明,对于10,000次迭代,“simplejson”2.6.2需要66.7秒,“msgpack”0.2.2只需要28.8。 – Day 2012-11-06 23:15:13

+0

[测试代码](http://pastebin.com/ZkS0kLB2)(pastebin) – Day 2012-11-06 23:21:05

+0

@Oleksiy请提供测试代码。 – 2012-12-07 20:41:34

13

我知道这个问题是在这一点上有点过时...我想提一提,它取决于你的客户机/服务器环境是什么样子是非常重要的。

如果要传递的字节多次未经检验,例如用一个消息队列系统或流式传输的日志条目到磁盘上,则很可能更喜欢的二进制编码来强调紧凑的尺寸。否则,这是一个在不同环境下的案例。

某些环境会有非常快速的序列化和反序列化到/从msgpack/protobuf的年代,别人没有这么多。一般来说,语言/环境越低级,更好的二进制序列化就可以工作。在更高级别的语言(node.js,.Net,JVM)中,您经常会看到JSON序列化实际上更快。那么问题就是你的网络开销比你的内存/ CPU多少受到限制?

至于msgpack VS BSON VS协议缓冲区... msgpack是该组的至少字节,协议缓冲区是大约相同的。 BSON定义了比其他两种更广泛的本机类型,并且可能与对象模式更匹配,但这使得它更加冗长。协议缓冲区具有被设计为流式传输的优势...这使得它成为二进制传输/存储格式更自然的格式。

我个人的偏向透明度JSON提供直接,除非有较轻的交通显然需要。通过使用压缩数据的HTTP,网络开销的差异更不是格式之间的问题。

+5

本机MsgPack *只有*效率与ProtocolBuffers尺寸明智的密钥长度(这是始终存在的文本)是*短*如“a”或“b” - *或否则是无意义的部分整个有效载荷*。在ProtocolBuffers中它们总是很短,它使用IDL /编译将字段描述符映射到ID。这也是什么使MsgPack“动态”,其中ProtocolBuffers是肯定不是.. – user2864740 2015-02-26 22:26:44

+0

终点是好的,虽然:gzip/deflate是*真的很好*处理密钥冗余的情况下,如果这些密钥是“更长,但重复很多“(MsgPack,JSON/BSON和XML等等* *许多*记录),但在这里完全无助于ProtocolBuffers。Avro通过单独传输模式手动完成关键冗余消除操作。 – user2864740 2015-02-26 22:27:25