你真的用对protobuf了吗?

历史

进程间数据交换有很多种方式,比如共享内存、网络通信、文件、数据库等等。如果你的数据并不是整齐有规律,且内存对齐的。大部分情况下,你都需要采用一种数据交换格式来描述你交换的数据,我们通常称之为序列化和反序列化。而描述这些数据的格式,我们通常称之为数据交换格式。

最原始的数据交换格式就类似于tcp/ip那样的描述,一般称之为二进制数据格式。每一层协议都有包头和包体,包头中会包含包体的长度,数据类型,保留字段dengdeng。当然,不要忘了还有块存储区域保存了数据的校验和。尽管这种格式可读性较差,但这种格式的序列化和反序列化效率是最高的。

二进制数据格式除了可读性较差以外,扩展性不好是开发者不会普遍采用的主要原因。于是就慢慢发展出了xml和json这两种自描述的数据交换格式。他们可读性强,有确定的schema。起先http的通信大部分基于soap协议,而soap离不开xml。随着前端技术的发展,尤其是javascript对json的支持,使得开发人员能很方便地序列化和反序列化json,于是json慢慢就成了web开发主流的数据交换格式。如今基本很少看到基于xml的接口了,除了部分陈旧的天气预报服务的订阅接口以外。

为什么选择protobuf

近几年,又陆续出现了二进制数据交换格式,比如Thrift、Protobuf,还有各大互联网公司自研的号称比protobuf更好的数据交换格式。其中,protobuf封装性更好,与平台语言都无关,使用会更广泛。

除了rest接约定俗称采用json以外,我们大部分采用protobuf的原因如下:

  1. 速度更快
  2. 空间更小
  3. 浮点数的精度支持不好,尤其是json
  4. xml、json都是文本型的,如果想存储二进制数据,必须先将其转为文本数据,比如使用base64编码
  5. 安全。json不同语言有各种各样的解析库,代码实现者信息安全经验良莠不齐,大部分库都有远程执行漏洞。而protobuf由谷歌官方维护,能很大程度上保证安全,一旦出现安全隐患也会很快更新。

大部分人只知道前面两点,并不了解后面三点protobuf的优势。

protobuf你用对了吗?

尽量使用proto3

相比于proto2,proto3更简洁,不需要用户指定required、optional关键字,这点除了开发更方便以外,对于前后兼容也是非常有帮助的,我将在下一条建议中说明。

版本号

有很多从json或其他协议转过来的人,还会保留以前那套协议版本号的做法。事实上,这样的做法非常恶心,代码里面会有大量的版本判断和处理。protobuf的设计初衷就是为了避免出现这样恶心的代码的。
具体请看a bit of historyExtending a Protocol Buffer

谷歌是这样讲的:

Protocol buffers were designed to solve many of these problems:

New fields could be easily introduced, and intermediate servers that didn’t need to inspect the data could simply parse it and pass through the data without needing to know about all the fields.

Formats were more self-describing, and could be dealt with from a variety of languages (C++, Java, etc.)

存储大量字符串

有些人会使用protobuf存储大量字符串,更有甚者可能会将json放入protobuf中。
如果有心人看过protobuf序列化之后的数据,会发现protobuf对字符串数据是直接拷贝的。所以使用protobuf存储字符串,并没有达到优化空间的目的。

二进制数据不需要加密

既然protobuf是二进制数据交换格式,那我们还有必要对其进行加密吗?
看过protobuf官方文档的人会知道,protobuf存储思路是这样的:对于不同字段,使用了tag来标识,而基本数据类型,使用了ZigZag类型存储,字符串直接拷贝。
换句话说,protobuf就类似与代码混淆一样,将字段名用简化后的字段名表示,只是可读性差一点。但里面所有的值都可以算出来。
所以如果安全对你的应用来说很重要的话,还是加密吧。


本文链接:http://www.servercoder.com/2018/01/10/protobuf-usages/