性能实体序列化:BSON与MessagePack(vs JSON)

Ale*_*lex 131 serialization bson deserialization messagepack msgpack

最近我发现了MessagePack,这是Google的Protocol BuffersJSON的替代二进制序列化格式,它也优于两者.

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

有人可以详细说明BSON与MessagePack差异和优势吗?


只是为了完成高效的 二进制序列化格式列表:还有Gobs将成为Google协议缓冲区的继承者.然而,与所有其他提到的格式相比,这些格式不是语言无关的,并且依赖于Go的内置反射,至少还有除Go之外的其他语言的Gobs库.

小智 183

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

格式设计

  1. 与JSON的兼容性

    尽管名称如此,但与MessagePack相比,BSON与JSON的兼容性并不高.

    BSON有特殊类型,如"ObjectId","Min key","UUID"或"MD5"(我认为这些类型是MongoDB所必需的).这些类型与JSON不兼容.这意味着当您将对象从BSON转换为JSON时,某些类型信息可能会丢失,但当然只有当这些特殊类型位于BSON源中时才会丢失.在单一服务中同时使用JSON和BSON可能是一个缺点.

    MessagePack旨在从/向JSON透明转换.

  2. MessagePack小于BSON

    MessagePack的格式比BSON简洁.因此,MessagePack可以序列化小于BSON的对象.

    例如,简单映射{"a":1,"b":2}使用MessagePack以7字节序列化,而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,Protocol Buffers,Thrift和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>();
    }
Run Code Online (Sandbox Code Playgroud)
  1. MessagePack有IDL

    它与类型检查API有关,MessagePack支持IDL.(规范可从以下网址获得:http://wiki.msgpack.org/display/MSGPACK/Design+of+IDL)

    Protocol Buffers和Thrift需要IDL(不支持动态类型)并提供更成熟的IDL实现.

  2. 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
    }
Run Code Online (Sandbox Code Playgroud)

  • MessagePack如何在数据大小方面与Google Protobufs进行比较,从而在空中表现方面如何? (32认同)
  • 第一点掩盖了MessagePack具有原始字节功能的事实,该功能无法用JSON表示.所以它在这方面与BSON一样...... (4认同)
  • @lttlrck通常,假设原始字节是一个字符串(通常是utf-8),除非另有预期并同意在通道的两侧.msgpack用作流/序列化格式......并且json的详细程度较低......但也不太可读. (3认同)
  • "MessagePack有类型检查API.BSON没有." 不完全准确.对于静态类型语言中的BSON实现,这实际上也是如此. (3认同)
  • 有人可以告诉我什么是“RPC”? (2认同)

Tra*_*er1 16

我知道这个问题在这一点上有点陈旧......我认为提到它取决于你的客户端/服务器环境是什么样的,这一点非常重要.

如果您在没有检查的情况下多次传递字节,例如使用消息队列系统或将日志条目传输到磁盘,那么您可能更喜欢使用二进制编码来强调紧凑的大小.否则,这是针对不同环境的个案问题.

有些环境可以对msgpack/protobuf进行非常快速的序列化和反序列化,而其他环境则没有那么多.通常,语言/环境越低级,二进制序列化就越好.在更高级的语言(node.js,.Net,JVM)中,您经常会看到JSON序列化实际上更快.那么问题就是你的网络开销或多或少比你的内存/ cpu约束?

关于msgpack vs bson vs协议缓冲区... msgpack是该组的最小字节,协议缓冲区大致相同.BSON定义了比其他两种更广泛的本机类型,并且可能更好地匹配您的对象模式,但这使它更加冗长.协议缓冲区的优点是可以设计为流...这使得它成为二进制传输/存储格式的更自然的格式.

就个人而言,我倾向于直接提供JSON提供的透明度,除非明确需要更轻的流量.通过带有gzip压缩数据的HTTP,网络开销的差异甚至不是格式之间的问题.

  • 由于密钥的长度(始终存在的文本)是*short*,例如"a"或"b" - *,否则本机MsgPack在协议缓冲区的大小方面只是***,或者在整个范围内是微不足道的一部分有效载荷*.它们总是在ProtocolBuffers中很短,它使用IDL/compile将字段描述符映射到id.这也是使MsgPack"动态"的原因,其中ProtocolBuffers绝对不是...... (6认同)
  • 不过,终点是好的:gzip/deflate *非常好* 在这些密钥“更长但重复很多”的情况下处理密钥的冗余(MsgPack、JSON/BSON 和 XML 等超过*许多*记录)但是在这里根本不会帮助 ProtocolBuffers .. Avro 通过单独传输模式来手动消除密钥冗余。 (2认同)

小智 11

那么\xef\xbc\x8cas 作者说\xef\xbc\x8cMessagePack 最初是为网络通信设计的,而 BSON 是为存储设计的。

\n\n

MessagePack 比较紧凑,而 BSON 比较冗长。\nMessagePack 旨在节省空间,而 BSON 则专为 CURD(节省时间)而设计。

\n\n

最重要的是,MessagePack的类型系统(前缀)遵循Huffman编码,这里我画了MessagePack的Huffman树(点击链接看图片)\xef\xbc\x9a

\n\n

MessagePack 的霍夫曼树

\n


Vin*_*nci 5

尚未提及的一个关键区别是 BSON 包含整个文档和进一步嵌套的子文档的大小信息(以字节为单位)。

document    ::=     int32 e_list
Run Code Online (Sandbox Code Playgroud)

这对于尺寸和性能都很重要的受限环境(例如嵌入式)有两个主要好处。

  1. 您可以立即检查要解析的数据是否代表完整的文档,或者您是否需要在某个时刻请求更多数据(无论是来自某些连接还是存储)。由于这很可能是异步操作,因此您可能在解析之前已经发送了新请求。
  2. 您的数据可能包含包含与您无关的信息的整个子文档。BSON 允许您通过使用子文档的大小信息来跳过它,从而轻松地遍历到子文档之后的下一个对象。另一方面,msgpack 包含所谓映射内的元素数量(类似于 BSON 的子文档)。虽然这无疑是有用的信息,但它对解析器没有帮助。您仍然必须解析地图内的每个对象,而不能跳过它。根据数据的结构,这可能会对性能产生巨大影响。