Protocol Buffers的应用
1. Protocol Buffers的介绍
Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages – Java, C++, or Python. You can even update your data structure without breaking deployed programs that are compiled against the “old” format.(摘自Protocol Buffers官网)
protocol buffers是google提供的一种将结构化数据进行序列化和反序列化的方法,其优点是语言中立,平台中立,可扩展性好,目前在google内部大量用于数据存储,通讯协议等方面。Protocol Buffers在功能上类似XML,但是序列化后的数据更小,解析更快,使用上更简单。用户只要按照proto语法在.proto文件中定义好数据的结构,就可以使用Protocol Buffers提供的工具(protoc)自动生成处理数据的代码,使用这些代码就能在程序中方便的通过各种数据流读写数据。PB目前支持Java, C++和Python3种语言。另外,Protocol Buffers还提供了很好的向后兼容,即旧版本的程序可以正常处理新版本的数据,新版本的程序也能正常处理旧版本的数据。
Protocol Buffers具有以下特点:
- 平台无关、语言无关
- 高性能 比XML块20-100倍
- 体积小 比XML小3-10倍
- 使用简单
- 兼容性好
2、message的编码特点
Protocol Buffers 之所以解析速度快、所占体积小,很大程度上是由它序列化的编码特点来决定的。
2.1 Base 128 Varints
Protocol Buffers采用了Base 128 Varints来变长编码整数:
- 变长编码的整数,它可能包含多个byte,对于每个byte的8位,其中后7位表示数值,最高的一位表示是否还有还有另一个byte,0表示没有,1表示有;
- 越前面的byte表示数值的低位,越后面的byte表示数值的高位;
例子:
300 varints 编码为:1010 1100 0000 0010
解释如下:
300的2进制编码为:0001 0010 1100
按照刚才的规则,高低位颠倒,截取最后的7为放在第一个byte,则第一byte为1010 1100(其中最高位1表示,后续还有byte);接着剩下的内容放到第二个byte,为0000 0010(其中最高位0表示,后续无byte,这个数到这里截止了)。
于是,合在一起为 1010 1100 0000 0010;
2.2 Key-Value
如前所述,Protocol Buffers的message是一系列的key-value对,在二进制数据中,使用varints数字(包含了别名以及属性类型信息)来作为key,进而通过由PB编译器生成的代码来构造以及解析数据。
Protocol Buffers将 key编码成下面的结构:
X YYYY ZZZ
其中:最高位X表示是否还有后续的byte来编码数字别名;YYYY用于编码别名,定义了多余16个属性,则需要用到额外的byte,所以出现频率高的字段应当取1-16的别名);ZZZ表示这个字段的类型,PB支持的属性的对应规则如下表:
Type | Meaning | Used For |
0 | Varint | int32, int64, uint32, uint64, sint32,sint64, bool, enum |
1 | 64-bit | fixed64, sfixed64, double |
2 | Length-delimited | string, bytes, embedded messages,packed repeated fields |
3 | Start group | groups (deprecated) |
4 | End group | groups (deprecated) |
5 | 32-bit | fixed32, sfixed32, floa |
表2:PB 属性对应规则
例子:
required int32 a=1; 在应用中给a赋值150 ,序列化后08 96 01
- 08代表的是key 0 0001 000, 最高位为0,表示这个key为一个byte,中间四位表示a的数字别名,最后三位表示a的属性类型;
- 96 01代表的是value,二进制为:1001 0110 0000 0001
→ 001 0110 000 0001(去掉最高位)
→ 22 + 1*2^7 = 150
2.3 Zig-Zag
采用varints的方式编码有符号的整数,效率比较差,因为负数的最高位是1,这样就导致了情况类似于编码一个很大的数。
为了解决这个问题,Protocol Buffers定义了sint32/sint64属性,他们采用了“之字形”(ZigZag)编码的方式,将负数编码成正数,交替进行。看了下表就很好理解了:
Signed Original | Encoded As |
0 | 0 |
-1 | 1 |
1 | 2 |
-2 | 3 |
2147483647 | 4294967294 |
2147483648 | 4294967295 |
表3:Zig-Zag编码规则
利用这个方式,可以有效地节省存储空间,也能提高解析效率。了解了以上内容,对于其他数据类型的编码,也是很好理解的,大家可以参考官方文档,这里不做详述。
3.为什么不用XML?
ProtocolBuffer拥有多项比XML更高级的串行化结构数据的特性,ProtocolBuffer:
· 更简单
· 小3-10倍
· 快20-100倍
· 更少的歧义
· 可以方便的生成数据存取类
例如,让我们看看如何在XML中建模Person的name和email字段:
<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>
对应的ProtocolBuffer报文则如下:
#ProtocolBuffer的文本表示
#这不是正常时使用的二进制数据
person {
name: "John Doe"
email: "jdoe@example.com"
}
当这个报文编码到ProtocolBuffer的二进制格式( http://code.google.com/apis/protocolbuffers/docs/encoding.html )时(上面的文本仅用于调试和编辑),它只需要28字节和100-200ns的解析时间。而XML的版本需要69字节(除去空白)和5000-10000ns的解析时间。
当然,操作ProtocolBuffer也很简单:
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
而XML的你需要:
cout << "Name: "
<< person.getElementsByTagName("name")->item(0)->innerText()
<< endl;
cout << "E-mail: "
<< person.getElementsByTagName("email")->item(0)->innerText()
<< end;
当然,ProtocolBuffer并不是在任何时候都比XML更合适,例如ProtocolBuffer无法对一个基于标记文本的文档建模,因为你根本没法方便的在文本中插入结构。另外,XML是便于人类阅读和编辑的,而ProtocolBuffer则不是。还有XML是自解释的,而 ProtocolBuffer仅在你拥有报文格式定义的 .proto 文件时才有意义。
相关文章:
.net自带二进制序列化,XML序列化和ProtoBuf序列化的压缩对比
Protocol Buffers and WCF http://blogs.msdn.com/b/dmetzgar/archive/2011/03/29/protocol-buffers-and-wcf.aspx
Protobuf-net: the unofficial manual http://www.codeproject.com/Articles/642677/Protobuf-net-the-unofficial-manual
Working with Protobuf WCF Services http://www.drdobbs.com/windows/working-with-protobuf-wcf-services/240159282?pgno=1
欢迎大家扫描下面二维码成为我的客户,扶你上云