写在前面

本文隶属于专栏《100个问题搞定大数据理论体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和文献引用请见100个问题搞定大数据理论体系

解答

Google Protocol Buffers(Protobuf)是一种轻便、高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或RPC数据交换格式。

它可用于通信协议、数据存储等领域的语言无关、平台无关扩展的序列化结构数据格式。

补充

优点

  1. 更小、更快——Protobuf类似XML,不过它更小、更快。用户可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构,甚至可以在无须重新部署程序的情况下更新数据结构。
  2. 跨平台、跨语言——只需使用 Protobuf对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对结构化数据进行轻松读/写。
  3. 向后兼容性好——它有一个非常棒的特性,即“向后”兼容性好,人们不必破坏已部署的、依靠“老”数据格式的程序就可以对数据结构进行升级。这样就可以不必担心因为消息结构的改变而造成大规模的代码重构或者迁移。
  4. 语义更清晰——Protobuf的语义更清晰,无须类似XML解析器的内容(因为Protobuf编译器会将.proto文件编译成对应的数据访问类,以对Protobuf数据进行序列化、反序列化操作)。
  5. 简单易学——使用Protobuf无须学习复杂的文档对象模型。 Protobuf的编程模式比较友好、简单易学,同时它拥有良好的文档和示例。对于喜欢简单事物的人而言, Protobuf比其他技术更有吸引力。

缺点

  1. 无法表示复杂概念——Protobuf与XML相比也有不足之处。它功能简单,却无法用来表示复杂的概念。
  2. 通用性不足——XML已经成为多种行业标准的编写工具,而Protobuf只是Google公司内部使用的工具,在通用性上相差很多由于文本并不适合用来描述数据结构,所以Protobuf也不适合用来对基于文本的标记文档(如HTML)建模。
  3. 无法自解释,可读性差——另外,由于XML具有某种程度上的自解释性,它可以被直接读取编辑。而Protobuf以二进制的方式存储,除非有proto定义,否则无法直接读出Protobuf的任何内容。
  4. Protobuf3 之前只支持Java/Python/C++,Protobuf3 以后开始支持 Go/Ruby/PHP 等。

Protobuf 为什么比 XML 快得多?

人们一直在强调,同XML相比, Protobuf的主要优点在于性能高。它以高效的二进制方式存储, 比XML小3~10倍,快20~100倍。

有两项技术保证了采用 Protobuf的程序能获得相对于XML极大的性能提高。

首先,可以考察 Protobuf序列化后的信息内容。可以看到 Protobuf信息的表示非常紧湊,这意味着消息的体积减小,自然需要更少的资源,如网络上传输的字节数更少、需要的1O更少等,从而提高性能。

其次,需要理解 Protobuf封解包的大致过程,从而理解它为什么会比XML快很多。

Protobuf 的 Encoding

Protobuf序列化后生成的二进制消息非常紧湊,这得益于 Protobuf来用了非常巧妙的 Encoding 方法。

在考察消息结构之前,首先介绍一个名为 Variant的术语。

Variant是一种紧凑地表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数,这样就能减少用来表示数字的字节数。

消息经过序列化后会成为一个二进制数据流,该流中的数据为一系列的Key/Value对。

采用这种Key/Value结构无须使用分隔符来分割不同的Field。对于可选的 Field,如果消息中不存在该Field,那么在最终的 MessageBuffer中就没有该 Field。

这些特性都有助于减少消息本身的大小。

Protobuf封解包的过程

首先来了解一下XML的封解包过程。

XML需要先从文件中读取字符串,再转换为XML文档对象结构模型,然后再从XML文档对象结构模型中读取指定节点的字符串,最后将这个字符串转换成指定类型的变量。

这个过程非常复杂,其中将XML文件转换为文档对象结构模型的过程通常需要完成词法、文法分析等大量消耗CPU的复杂计算。

反观 Protobuf,只需简单地将一个二进制序列按照指定的格式读取到C++对应的结构类型中即可,速度非常快。

通常编写一个 Google Protocol Buffer应用需要以下几步:

  1. 定义消息格式文件,文件通常以.proto作为后缀名结尾;
  2. 使用 Google提供的 Protocol Buffer环境进行文件编译,编译成指定的(Java、Python、C++等)文件;
  3. 使用 Protocol Buffer提供的应用接口(API)类库来完成业务程序开发。

Q.E.D.


Apache Spark Contributor