個人小站,正在持續整理中,歡迎訪問:http://shitouer.cn
小站博文地址:Google Protocol Buffers 概述
推薦閱讀順序,希望給你帶來收獲~
《Google Protocol Buffers 編碼(Encoding)》
1. 概述
Protocol Buffers 是一種輕便高效的結構化數據存儲格式,可以用於結構化數據串行化,或者說序列化。它很適合做數據存儲或 RPC 數據交換格式。可用於通訊協議、數據存儲等領域的語言無關、平台無關、可擴展的序列化結構數據格式。目前提供了 C++、Java、Python 三種語言的 API。
本文概述介紹Protocol Buffers,以及開始如何開始Protocol Buffers之旅,本系列主要以Java為主(雖然超想看Python的,無奈學的還不夠...)。
以下Protocol Buffers簡稱PB。
2. Protocol Buffers是什么
Protocol Buffers提供了一種靈活,高效,自動序列化結構數據的機制,可以聯想XML,但是比XML更小,更快,更簡單。僅需要自定義一次你所需的數據格式, 然后用戶就可以使用Protocol Buffers自動生成的特定的源碼,方便的讀寫用戶自定義的格式化的數據。不限語言,不限平台。還可以在不破壞原數據格式的基礎上,依據老的數據格式, 更新現有的數據格式。
3. Protocol Buffers如何工作的
在PB中,有一種.proto類型的文件,用戶 在.proto文件中定義PB “Message”來指定所需要序列化的數據的格式。每一個PB Message都是一個小的信息邏輯單元,包含了一些列的name-value對。下面舉例說明一個簡單地.proto文件,他定義了一條包含一個 Person信息的Message:
message Person { required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; }
如上代碼所示,PB message 格式非常簡單。每種類型的message包含一個或者多個唯一編碼字段,每個字段由名稱和值類型組成,值類型可以使數字(整形或者浮點型),布爾值,字符 串,原始字節,甚至是其他的PB message。PB允許message中包含message,已達到分層嵌套。可以定義可選字段,必填字段以及重復字段。想要了解更多如何 寫.proto 文件,可以訪問:Protocol Buffer Language Guide
定 義好PB message后,選擇合適語言的PB編譯器,編譯.proto文件,就可以生成存取數據的相關類。這些類包括簡單的設置及讀取字段的方法,也包括對整個 數據結構的message與二進制之間的轉換。舉個例子,如果你使用的語言是java,運行編譯器編譯上例.proto文件后,生成的類中包含一個 Person類。使用該類,就可以計算,序列化以及檢索PB message。如下代碼:
public static void main(String[] args) throws IOException { Person john = Person .newBuilder() .setId(1) .setName("john") .setEmail("john@youku.com") .addPhone( PhoneNumber .newBuilder() .setNumber("1861xxxxxxx") .setType(PhoneType.WORK) .build()) .build(); FileOutputStream output = new FileOutputStream("abc.txt"); john.writeTo(output); output.close(); }
接下來,你可以用如下代碼讀取:
public static void main(String[] args) throws IOException { FileInputStream input = new FileInputStream("abc.txt"); Person person = Person.parseFrom(input); System.out.println(person.getId()); System.out.println(person.getName()); System.out.println(person.getEmail()); System.out.println(person.getPhoneCount()); System.out.println(person.getPhone(0).getNumber()); System.out.println(person.getPhone(0).getType()); }
PB是易於擴展的,可以向后兼容的,我們可以在PB message中添加新的字段,這樣,在parse的時候,老版本的數據就會簡單的忽略新增加的字段。因此,如果現有通信協議使用了PB作為其數據格式,我們可以直接擴展該通信協議,而不必擔心這將會破壞現有的代碼。
對於使用.proto文件生成PB 客戶端代碼,可以參看這方面的完整教程:API Reference section。想要學習了解PB message是如何編碼的,可以參見:Protocol Buffer Encoding。
4. 為什么不直接使用XML呢?
如果要序列化結構化數據,比起XML,PB實在是有許多的優點可以道道~
- 更簡單
- 比XML小3~10倍
- 比XML快20~100倍
- 語義定義明確
- 自動生成數據存取類,更容易使用
假如我們要模擬一個Person,該對象包含name和email屬性,如果用XML,我們定義如下:
<person> <name>John Doe</name> <email>jdoe@example.com</email> </person>
對應的,PB如下:
person { name: "John Doe" email: "jdoe@example.com" }
請注意:這里僅是PB格式的一種直觀表示,真實的PB並非這樣存儲,實際上,在鏈路中,PB數據時二進制格式的。
當這段數據編碼為PB二進制格式時,其實際大小大概是28bytes,編碼時間為100~200納秒。如果用XML的話,即使去除空格,大小也至少為69bytes,編碼時間大概需要5000~10,000納秒。
同樣,解析這段代碼,PB比XML要方便許多。用PB的話:
person.getName(); person.getEmail();
而用XML的話:
personNode.getElementsByTagName("name") personNode.getElementsByTagName("email")
相比起來,PB更直接,而且不需要遍歷節點等XML操作。
但是,金無足赤,人無完人,PB也一樣。對於有很多標簽的,基於文本的數據(例如HTML),XML就完勝PB。XML是子描述的,可以隨機且交錯讀取讀取文本節點。XML是自描述的,而PB不是,PB必須要有格式定義文件(.proto 文件)
5. 一點歷史
PB由Google開發,最初是用於處理索引服務器的請求/響應協議。在有PB之前,Google使用手動編組和解組的方式來處理請求/相應協議。這種方式需要支持許多版本的協議,這就導致一些代碼非常的丑陋,例如:
if (version == 3) { ... } else if (version > 4) { if (version == 5) { ... } ... }
另外,這種顯示格式的協議同樣將新發布的協議版本也搞得非常復雜,因為開發者必須在啟用新的協議之前,確認所有的服務器,包括請求的發起者以及實際處理請求者,他們都能夠理解新的協議。
PB即被設計來解決這些問題:
- 要可以非常容易的引入新字段,不需要檢查數據的中間服務器 能夠簡單地解析數據,並且無須知道數據所有的字段就可以傳輸數據。
- 格式能夠更加的自描述一些,並且可以被多用語言處理(C ++, Java,Python等)
至此,雖然解決了諸多問題,但用戶依然需要手寫他們的解析及編碼代碼。
隨着系統的發展,PB逐漸形成了許多新的特性及用法:
- 自動生成序列化及反序列化代碼,避免手動解析
- 除了被用在短生命周期的RPC請求,也開始將PB作為一種方便的自描述格式去存儲持久化數據。
- Server RPC interfaces 開始被聲明為協議文件的一部分,使用PB compiler 生成stub類,用戶可以使用自己實現的服務器接口來覆蓋他們。
Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標准,目前已經正在使用的有超過 48,162 種報文格式定義和超過 12,183 個 .proto 文件。他們用於 RPC 系統和持續數據存儲系統。
譯自:https://developers.google.com/protocol-buffers/docs/overview
初次嘗試翻譯,諸多不夠信達雅之處,還望能夠不吝指出不到之處,謝謝~