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序列化的壓縮對比
WCF服務上應用protobuf
玩轉Protocol Buffers
Beetle使用Protobuf.net進行對象序列化傳輸
Google Protocol Buffer 的使用和原理
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
?