了解一下ProtoBuf

序列化與反序列化

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

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

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

而另外一個我們熟知的則是JSON(JavaScript Object Notation, JS 對象簡譜)苛茂。盡管JSON中缺少了XML中的標簽屬性等描述方式,但是足夠簡介和清晰的層次結(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中缺少的類型定義被定義道程序中的接口中了净刮。當進行序列化與反序列化時,JSON格式并不記錄數(shù)據(jù)的類型硅则,具體的數(shù)據(jù)類型在序列化方與反序列化方通過事先約定的接口來進行定義庭瑰。這樣就減少了信息傳輸過程中的信息量,從而讓數(shù)據(jù)得以壓縮抢埋。

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

ProtoBuf的原理概要

結(jié)合上文的討論穷吮,我們先說結(jié)論:方法是有的,并寫當前的實現(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 更写沉健(3 ~ 10倍)、更快(20 ~ 100倍)谅将、更為簡單漾狼。 你可以定義數(shù)據(jù)的結(jié)構(gòu),然后使用特殊生成的源代碼輕松地在各種數(shù)據(jù)流中使用各種語言進行編寫和讀取結(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原理借嗽,但是可以通過一張圖來進行簡要說明(圖片來自網(wǎng)絡):

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

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

稍微總結(jié)一下:

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

二進制序列化

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

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

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

使用ProtoBuf

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

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

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

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

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

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

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

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

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

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

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

最后

本文對ProtoBuff進行了概念的整理壶冒,并沒有對每個細節(jié)都進行深入的梳理缕题,可以當作概念科普來進行閱讀。



?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胖腾,一起剝皮案震驚了整個濱河市烟零,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌咸作,老刑警劉巖锨阿,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異记罚,居然都是意外死亡墅诡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門桐智,熙熙樓的掌柜王于貴愁眉苦臉地迎上來末早,“玉大人烟馅,你說我怎么就攤上這事∪涣祝” “怎么了郑趁?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長姿搜。 經(jīng)常有香客問我寡润,道長,這世上最難降的妖魔是什么痪欲? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任悦穿,我火速辦了婚禮,結(jié)果婚禮上业踢,老公的妹妹穿的比我還像新娘栗柒。我一直安慰自己,他們只是感情好知举,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布瞬沦。 她就那樣靜靜地躺著,像睡著了一般雇锡。 火紅的嫁衣襯著肌膚如雪逛钻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天锰提,我揣著相機與錄音曙痘,去河邊找鬼。 笑死立肘,一個胖子當著我的面吹牛边坤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谅年,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼茧痒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了融蹂?” 一聲冷哼從身側(cè)響起旺订,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎超燃,沒想到半個月后区拳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡意乓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年劳闹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洽瞬。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡本涕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伙窃,到底是詐尸還是另有隱情菩颖,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布为障,位于F島的核電站晦闰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鳍怨。R本人自食惡果不足惜呻右,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞋喇。 院中可真熱鬧声滥,春花似錦、人聲如沸侦香。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽罐韩。三九已至憾赁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間散吵,已是汗流浹背龙考。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矾睦,地道東北人晦款。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像顷锰,于是被迫代替她去往敵國和親柬赐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容