05.Protocol Buffers技巧

翻译自: Techniques

本文讨论Protocol Buffers在数据交换时,常用的一些设计模式。

序列化多个消息

如果要在一个文件或者一个流中写入多条消息,此时需要追踪消息的结尾位置与下一条消息的开始位置。Protocol Buffers无法自定边界,也就是说,proto解析器无法确定消息的结尾位置。最简单的解决方案是在写入消息前,先写入固定长度的消息size值,在读取流时,先从流中读取固定长度的size,然后读取消息长度的数据,放到一个特定的buffer,再使用解析器解析这个buffer。(如果要拷贝部分字节到一个特定的buffer,可以看一下Java和C++类的CodedInputStream类)

大型数据集合

Protocol Buffers的设计不适用于大型数据处理,按照一般经验来说,超过1M字节的数据,就应该另选其它的方案了。

也就是说,Protocol Buffers适合处理数据集中的独立元素。通常情况下,大型数据集实际上是小数据的集合,其中每个一元素都是结构化的数据。虽然Protocol Buffers不适合处理整个数据集合,但是,可以使用Protocol Buffers处理集合中的每一个元素。

Protocol Buffers不包含任何处理大型数据集合的内置支持,因为实际应用中,不同的情况需要不同的处理方案,每个解决方案都需要开发一个独立库。

自描述消息

Protocol Buffers不包含类型描述信息,所以,如果只给出一个原始消息,而没有相应的.proto文件定义其类型,那么,解析消息将变的非常困难。

然而.proto文件本身可以使用Protocol Buffers来表示,源代码包中的src/google/protobuf/descriptor.proto定义了所涉及消息类型格式。protoc程序可以使用--descriptor_set_out选项输出FileDescriptorSet——代表一组.proto文件。这样就可以定义自描述消息了。

syntax = "proto3";

import "google/protobuf/any.proto";
import "google/protobuf/descriptor.proto";

message SelfDescribingMessage {
  // Set of FileDescriptorProtos which describe the type and its dependencies.
  google.protobuf.FileDescriptorSet descriptor_set = 1;

  // The message and its type, encoded as an Any message.
  google.protobuf.Any message = 2;
}

通过使用像DynamicMessage这样的类(Java和C++可用),可以编写工具去操作SelfDescribingMessage

未在Protocol Buffers库中包含这个功能的原因是在google内部从来没有使用过这个功能,所以在使用自描述消息之前,请检查您的平台是否支持此功能。