最近,我找到了MessagePack,这是Google协议缓冲区和JSON的另一种二进制序列化格式,它的性能也优于两者。
另外,MongoDB还使用了BSON序列化格式来存储数据。
有人可以详细说明BSON与MessagePack的区别和缺点吗?
只是为了完成高性能二进制序列化格式的列表:还有Gob,它们将成为Google协议缓冲区的后继者。但是,与所有其他提到的格式相反,这些格式不是语言不可知的,并且依赖于Go的内置反射,此外还有Gobs库,至少可以使用除Go之外的其他语言。
最佳答案
//请注意,我是MessagePack的作者。这个答案可能有偏见。
格式设计
- 与JSON的兼容性
- 尽管名称如此,但BSON与JSON的兼容性与MessagePack相比并不是很好。
- BSON具有特殊类型,例如“ ObjectId”,“ Min key”,“ UUID”或“ MD5”(我认为MongoDB需要这些类型)。这些类型与JSON不兼容。这意味着当您将对象从BSON转换为JSON时,某些类型信息可能会丢失,但是当然只有当这些特殊类型在BSON源中时,这些信息才会丢失。在单个服务中同时使用JSON和BSON可能是不利的。
- MessagePack旨在透明地从JSON转换为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,协议缓冲区,节流和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
}