谷歌protobuf和大型二进制blob

jan*_*jan 5 rpc protocol-buffers

我正在构建一个软件来远程控制连接到另一台PC的无线电硬件.

我计划使用ZeroMQ进行传输,并使用类似RPC的请求 - 回复,并在其上面显示代表操作的不同消息.

虽然我的大多数消息只是一些控制和状态信息,但应该有一个选项来设置要传输的数据blob或请求接收的blob数据.这些数据blob通常在5-10MB范围内,但也应该可以使用大到100MB的更大的blob.

对于消息格式,我发现谷歌协议缓冲区非常吸引人,因为我可以在传输链接上定义一个消息类型,它具有所有命令和响应的可选元素.但是,protobuf常见问题解答表明,如此大的消息会对性能产生负面影响.

所以问题是,它实际上有多糟糕?会有什么负面影响?我真的不想将整个通信基于protobuf,只是为了发现它不起作用.

Ken*_*rda 14

坦率地说,它本身的性能并不是因为库的设计方式可能不像你想要的那样处理大型消息.例如,您必须一次解析所有消息,并将其全部序列化.因此,如果您有一条包含100MB blob的消息,除非您读取整个100MB并在解析时阻止调用线程,否则您无法读取消息的任何部分.同样有问题的是,100MB blob将被分配为一个巨大的扁平字节数组.在64位系统上,这可能没问题,但在32位上,您可能会遇到地址空间碎片问题.最后,硬盘大小限制为2GB.

如果您对这些问题感到满意,那么您几乎可以做到这一点.您必须手动覆盖邮件大小限制,出于安全考虑,默认为64MB.为此,您需要CodedInputStream手动构造并SetTotalBytesLimit()在解析消息之前调用它.

但我个人建议尝试设计你的系统,以便大块可以分成小块.

  • @SBalough确实,我写了那篇文章.:) (7认同)
  • 分块是推荐的方法:_Protocol 缓冲区非常适合处理大型数据集中的单个消息。通常,大数据集实际上只是小块的集合,其中每个小块可能是结构化数据。尽管 Protocol Buffers 无法一次处理整个集合,但使用 Protocol Buffers 对每个部分进行编码可以极大地简化您的问题:现在您需要的只是处理一组字节字符串而不是一组结构。_ - https://developers .google.com/protocol-buffers/docs/techniques#large-data (2认同)
  • @speedplane如果你把它们放在`bytes`类型的字段中应该没问题. (2认同)

jap*_*iss 4

我没有时间为你做这件事,但我会浏览Protobuf 源代码。更好的是,继续使用大bytes字段编写代码,从源代码构建 protobuf,并在调试器中单步调试它,看看发送和接收大 blob 时会发生什么。

根据经验,我可以告诉您,大repeated Message字段除非具有该属性,否则效率[packed=true]高,但这仅适用于原始类型。

我的直觉是大面积的bytes田地会更有效率,但这完全没有根据。

您还可以绕过 Protobuf 来处理大 blob:

message BlobInfo {
    required fixed64 size;
    ...
}

message MainFormat {
    ...
    optional BlobInfo blob;
}
Run Code Online (Sandbox Code Playgroud)

那么你的解析代码如下所示:

...
if (message.has_blob()) {
    uint64_t size = msg.blob()->size();
    zmqsock.recv(blob_buffer, size);
}
Run Code Online (Sandbox Code Playgroud)