几个工具的比较

这里讨论 boost.serialization、avro、protocol buffer 和 thrift 这四个工具。

boost.serialization

前面讨论过这个库的基本用法,我们需要强调的是 boost.serialization 的设计是非常具有扩展性的,我们可以使用不同的 archive 实现支持不同的 serialization 策略,比如后面说的 avro,又或者 YAML(这个不知道能用不)、JSON 等格式。实现一个 archive 我们需要理解 archive 的 concept,有两个概念一个是 saving archive(SA)一个是 loading archive(LA),他们都实现了 is_saving、is_loading 返回 boost::mpl::bool_ 的 static 方法,register_type 用来注册类型,和 get_library_version 获得版本信息;前者还需要实现 operator<< 和 operator& 这是用来存放数据的函数,save_binary 用来向 archive 添加指定数目的 bytes;后者需要实现 operator>> 和 operator&,这是用来读取数据的函数,reset_object_address 用来重写地址,delete_created_pointers 用来清理掉产生的额外的 pointer。

avro

这是 apache 下的 hadoop 的衍生项目,从某种意义上来说 hadoop 自身的 Writable 接口能力非常有限,需要一些更加灵活的 serialization 的策略,这个策略下可以为一般的对象进行存储,方便 map/reduce job,在此基础上,上层的应用如 pig/hbase 等就可以利用这个策略。比较常见的问题是如 PIG,load 数据的时候必须在当时提供 schema,avro 从某种意义上其存储也包括了 schema 自身,这样 PIG 就能较为自动的为产生表建立我们需要的 schema(相关例子在此)。avro 的 schema 是用 JSON 格式写的,其规范见这里。如果想玩玩,首先需要 checkout 代码(居然没 tar ball..)

svn checkout http://svn.apache.org/repos/asf/avro/trunk avro

avro 也提供了 C++ 的 binding(文档见此),它提供了一个默认的 build.sh,不过既然是 CMake 系我们还是自己编译安装到自己喜欢的地方(默认是 /usr/local):

$ pwd
/some/where/avro/lang/c++
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/some/where/I/specify ../
$ make
$ make test
$ make install

我们实验一下 avro 文档中给的例子,发现其实 avro 使用的是类似 boost.serialization 里面的 non-intrusive 类型的 serialize 的策略,对一个外部的数据类型(并非使用 avrogencpp 通过 schema 生成的),我们需要在 avro namespace 提供 codec_traits,这个 traits 包含 encode 和 decode,其实早些时候为 hadoop streaming 写的一个 framework 里面当时增加了一层 base64 编码层跟这个策略使用的技巧如出一辙。下面是一个简单的 JSON 格式的 schema,

{
    "type": "record",
    "name": "cpx",
    "fields" : [
        {"name": "re", "type": "double"},
        {"name": "im", "type" : "double"}
    ]
}

一个很重要的功能是,我们除了使用原配的数据结构 recover 以外,还可以使用 GenericDatum 或者 compatible schema 的数据结构。比如

avro::GenericDatum datum(cpxSchema);
avro::decode(*d, datum);
std::cout << "Type: " << datum.type() << std::endl;
if (datum.type() == avro::AVRO_RECORD) {
const avro::GenericRecord& r = datum.value<avro::GenericRecord>();
std::cout << "Field-count: " << r.fieldCount() << std::endl;
if (r.fieldCount() == 2) {
const avro::GenericDatum& f0 = r.fieldAt(0);
if (f0.type() == avro::AVRO_DOUBLE) {
std::cout << "Real: " << f0.value<double>() << std::endl;
}
const avro::GenericDatum& f1 = r.fieldAt(1);
if (f1.type() == avro::AVRO_DOUBLE) {
std::cout << "Imaginary: " << f1.value<double>() << std::endl;
}
}
}

std::auto_ptr<avro::InputStream> in
= avro::memoryInputStream (*out) ;
avro::DecoderPtr d = avro::resolvingDecoder(cpxSchema,
imaginarySchema, avro::binaryDecoder ());
d->init (*in);
demo2::cpx c2;
avro::decode (*d, c2);

这表示数据的 schema 是可以动态的进行验证,拆分使用的。同时 avro 的 Java API 提供了对应 hadoop mapreduce 的 Inpu t/OutputFormat:如 AvroAsTextInputFormat 与 AvroTextOutputFormat 将 avro 转换成为 JSON 当做文本进行 streaming,还有 AvroKey/KeyValueInput/OutputFormat 可以指定需要的 key/value 作为 native code 的 keyvalue。另外 avro 也提供对 protocol buffer 和 thrift 的支持,这样允许直接读如这两种数据而当做 avro 来进行处理。

protocol buffer

从某种意义上来说 google 提供的 protobuf 并不是一个一味做 serialization 的东西,而是重在“通信”,也就是解决 RPC 中间的 message,它希望 message 小巧,通过它搞定的其实不是 serialization task 里面那些东西,而是强调简单的定义 message,然后能够生成 message 相关的代码供后面使用。文档可以参考这里。protobuf 的好处在于提供了一个容器(消息容器),这个消息的大小不是固定的,比如例子里面电话号码可以有多个,这些都是通过 protoc 编译 .proto 文件产生的代码实现的,也是调用了 protobuf 里面一些容器、消息类等。protobuf 甚至不考虑怎么为已有类建立对应消息。protobuf 有自己的的所谓 IDL 描述消息(文档)。因此可以看成是一个比较封闭的体系。protobuf 一个比较重要的功能是它实现了一个基本的 reflection(我们知道 C++ 其实没啥 reflection),这也是得益于这种封闭的设计吧。

thrift

apache thrift 是 facebook 那边搞出来的东西,用 auto-tools 做的编译管理,很容易就可以安装上(macports 提供支持),它的角色也和 protobuf 类似,重在通信方面而不是一个 serialization 的工具,特别是列在 non-feature 里面的很多东西都是 boost.serialization 所强调一定要具有的。使用 thrift 和 protobuf 很像,很多东西都一致的,但是似乎支持的语言多很多,这倒是呗 avro 继承了。这是其 IDL 的说明

小结

由此看来设计 serialization 和 RPC message 两个东西需要的库的特点是不大一样的,前两者注重的 serialization 的可扩展,特别是 avro 的特点可能就是支持动态的验证 schema 进行访问。后两者注重的是消息本身短小,解析快速。

——————-
And the water was spent in the bottle, and she cast the child under one of the shrubs.

Advertisements
几个工具的比较

一个有关“几个工具的比较”的想法

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s