了解一下ProtoBuf

序列化與反序列化

我們在進(jìn)行網(wǎng)絡(luò)通信調(diào)用的時候,總是需要將內(nèi)存的數(shù)據(jù)塊經(jīng)過序列化,轉(zhuǎn)換成為一種可以通過網(wǎng)絡(luò)流進(jìn)行傳輸?shù)母袷?。而這種格式在經(jīng)過了傳輸之后再經(jīng)過序列化,能還原成我們預(yù)想中的數(shù)據(jù)結(jié)構(gòu)。

那么我們對于這種用于中間網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)格式就有一定的要求。首先它可以準(zhǔn)確地描述數(shù)據(jù)內(nèi)容,在此基礎(chǔ)上我們則希望它盡量的小。

最開始流行起來的是XML,可擴展標(biāo)記語言。由于它可以用來標(biāo)記數(shù)據(jù)、定義數(shù)據(jù)類型,所以用戶可以自己定義數(shù)據(jù)自己的語言,從而讓對不同的數(shù)據(jù)結(jié)構(gòu)化成統(tǒng)一的格式稱為了可能。

而另外一個我們熟知的則是JSON(JavaScript Object Notation, JS 對象簡譜)。盡管JSON中缺少了XML中的標(biāo)簽屬性等描述方式,但是足夠簡介和清晰的層次結(jié)構(gòu)使得其成為了必XML更受歡迎的數(shù)據(jù)交換格式。

同一份數(shù)據(jù)顯然JSON的數(shù)據(jù)量比XML所使用的空間更少。那么空間省略在哪里呢?一方面是json使用更簡單的字符來定義數(shù)據(jù)間的關(guān)聯(lián)關(guān)系;另一方面是JSON減少了對數(shù)據(jù)類型的描述。但是丟少的數(shù)據(jù)類型再哪里呢?

以Java中的 OpenFeign 舉例,JSON中缺少的類型定義被定義道程序中的接口中了。當(dāng)進(jìn)行序列化與反序列化時,JSON格式并不記錄數(shù)據(jù)的類型,具體的數(shù)據(jù)類型在序列化方與反序列化方通過事先約定的接口來進(jìn)行定義。這樣就減少了信息傳輸過程中的信息量,從而讓數(shù)據(jù)得以壓縮。

但是JSON由于沒有定義數(shù)據(jù)類型,所以在傳輸?shù)倪^程中實際上就都是文本流,那么這種方法還可以進(jìn)一步壓縮嗎?

ProtoBuf的原理概要

結(jié)合上文的討論,我們先說結(jié)論:方法是有的,并寫當(dāng)前的實現(xiàn)方式是ProtoBuf。但在此之前我們先來了解一下ProtoBuf。

我們可以先看看官方給出的定義與描述:

protocol buffers 是一種與語言無關(guān)、平臺無關(guān)、可擴展的序列化結(jié)構(gòu)數(shù)據(jù)的方法,它可用于(數(shù)據(jù))通信協(xié)議、數(shù)據(jù)存儲等。 Protocol Buffers 是一種靈活,高效,自動化機制的結(jié)構(gòu)數(shù)據(jù)序列化方法-可類比 XML,但是比 XML 更?。? ~ 10倍)、更快(20 ~ 100倍)、更為簡單。 你可以定義數(shù)據(jù)的結(jié)構(gòu),然后使用特殊生成的源代碼輕松地在各種數(shù)據(jù)流中使用各種語言進(jìn)行編寫和讀取結(jié)構(gòu)數(shù)據(jù)。你甚至可以更新數(shù)據(jù)結(jié)構(gòu),而不破壞由舊數(shù)據(jù)結(jié)構(gòu)編譯的已部署程序。

同樣的,ProtoBuf也是一種支持序列化反序列化的方法,并且他具有很多優(yōu)點:

  1. 多語言
  2. 多平臺
  3. 體積小
  4. 擴展性好

實際上,ProtoBuf提供了一種通用的數(shù)據(jù)描述方式,這種定義數(shù)據(jù)的方式是通用的,就如同JSON或者XML一樣。

接下來我們來來回答本節(jié)一開始的問題,針對JSON來說,ProtoBuf是如何將體積變得更小的呢?答案很簡單,就是為數(shù)據(jù)序列化反序列化提供更多的先驗知識。

本文暫不過度深入ProtoBuf原理,但是可以通過一張圖來進(jìn)行簡要說明(圖片來自網(wǎng)絡(luò)):

ProtoBuf中的數(shù)據(jù)是按順序進(jìn)行排列,而整體的結(jié)構(gòu)為若干個field,每一個field中由Tag-[Length]-Value組成。Length是可選的,而是否存在Length是通過Tag的類型來決定的。也就是說如果是指定的類型,比如int64,那我們就可以知道Value的長度,也就不用在依靠Length來對其空間進(jìn)行描述(redis中的壓縮列表也是這個思想)。

那么field應(yīng)該對應(yīng)的是什么字段呢?這個則是在序列化與反序列化時在ProtoBuf的服務(wù)端與客戶端之間進(jìn)行預(yù)先定義的。而因為提前定義了field的類型、排序,所以field本身可以不用對字段名、字段位置進(jìn)行描述,只需要根據(jù)字段類型選用合適的二進(jìn)制序列化方法,將字段本身的value值進(jìn)行序列化傳輸即可。

稍微總結(jié)一下:

ProtoBuf通過對傳輸字段的名稱、順序進(jìn)行預(yù)定義,從而在傳輸結(jié)構(gòu)中只需要順序的記錄每個字段的類型標(biāo)簽和二進(jìn)制值。

二進(jìn)制序列化

盡管上文和官方中都是以XML或者JSON來對ProtoBuf進(jìn)行對比。但是因為ProtoBuf本身就是二進(jìn)制序列化方式,所以從壓縮比上比較感覺有點欺負(fù)人。

對應(yīng)的在Java中二進(jìn)制常用的序列化器有Kryo和Hessian。但事實上,由于Kryo和Hessian中都需要對Java類名和字段信息進(jìn)行存儲。而ProtoBuf則只有Tag-Length-Value的數(shù)據(jù)對,且Value更是有針對性的特殊編碼,所以空間占用小的很多。

Kryo是專門針對Java進(jìn)行優(yōu)化了的。所以在使用的便捷性上來說Kryo則更加方便。但ProtoBuf是跨平臺的,且由于進(jìn)行了字段的順序定義,所以似的ProtoBuf定義后的接口是可以向前兼容的(只向后追加字段),而這種優(yōu)勢是Kryo所沒有的。

使用ProtoBuf

ProtoBuf是跨語言的,使用ProtoBuf的第一步是先定一個proto 文件,而由于ProtoBuf 2和3語言版本的不同,其定義格式會有所不同,具體的細(xì)節(jié)還是得參考官方文檔:https://developers.google.cn/protocol-buffers/docs/proto3

對于ProtoBuf 3 的定義文檔我們可以按如下方法定義:

syntax = "proto3";//指定版本為proto3,默認(rèn)為proto2message SearchRequest { string query = 1; int32 page_number = 2; repeated int32 result = 3;}

其中message關(guān)鍵字是定義的文件名,而 string、int32則是預(yù)定的字段類型,repeated則是描述字段為可重復(fù)任意多次的字段。

ProtoBuf通過這種形式的文件定義了傳輸信息的文件結(jié)構(gòu)。

但是之前小節(jié)中我們知道了ProtoBuf是通過Tag-[Length]-Value組成的數(shù)據(jù)組來進(jìn)行信息傳輸?shù)模敲磒roto文件中定義的內(nèi)容如何轉(zhuǎn)換為實際傳輸?shù)膶ο竽兀?/p>

ProtoBuf的做法是,為每一種語言提供一個生成器protoc。通過使用protoc則可以根據(jù).proto文件生成為一組java文件。對應(yīng)的官方語法演示樣例為:

protoc --proto_path=src --java_out=build/gen src/foo.proto

官方的生成參考為:https://developers.google.com/protocol-buffers/docs/reference/java-generated

生成后的java文件將提供對應(yīng)的實體以及數(shù)據(jù)的構(gòu)造方法等文件,從而支持后續(xù)的使用。

需要注意的是,ProtoBuf是本質(zhì)上是序列化方法,具體是通過Spring Cloud 的OpenFeign進(jìn)行接口調(diào)用,還是通過grpc進(jìn)行接口調(diào)用,都是可以的。

最后

本文對ProtoBuff進(jìn)行了概念的整理,并沒有對每個細(xì)節(jié)都進(jìn)行深入的梳理,可以當(dāng)作概念科普來進(jìn)行閱讀。



?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容