Apache Avro是什么干什么用的(RPC/序列化)

Avro總結(jié)(RPC/序列化)

Avro(讀音類似于[?vr?])是Hadoop的一個子項目,
由Hadoop的創(chuàng)始人Doug Cutting(也是Lucene,Nutch等項目的創(chuàng)始人,膜拜)牽頭開發(fā),

Avro是一個數(shù)據(jù)序列化系統(tǒng),設(shè)計用于支持大批量數(shù)據(jù)交換的應(yīng)用。

它的主要特點有:支持二進制序列化方式,可以便捷,快速地處理大量數(shù)據(jù);動態(tài)語言友好,Avro提供的機制使動態(tài)語言可以方便地處理Avro數(shù)據(jù)。

當(dāng)前市場上有很多類似的序列化系統(tǒng),如Google的Protocol Buffers, Facebook的Thrift。這些系統(tǒng)反響良好,完全可以滿足普通應(yīng)用的需求。針對重復(fù)開發(fā)的疑惑,Doug Cutting撰文解釋道:Hadoop現(xiàn)存的RPC系統(tǒng)遇到一些問題,如性能瓶頸(當(dāng)前采用IPC系統(tǒng),它使用Java自帶的DataOutputStream和DataInputStream);需要服務(wù)器端和客戶端必須運行相同版本的Hadoop;只能使用Java開發(fā)等。但現(xiàn)存的這些序列化系統(tǒng)自身也有毛病,以Protocol Buffers為例,它需要用戶先定義數(shù)據(jù)結(jié)構(gòu),然后根據(jù)這個數(shù)據(jù)結(jié)構(gòu)生成代碼,再組裝數(shù)據(jù)。如果需要操作多個數(shù)據(jù)源的數(shù)據(jù)集,那么需要定義多套數(shù)據(jù)結(jié)構(gòu)并重復(fù)執(zhí)行多次上面的流程,這樣就不能對任意數(shù)據(jù)集做統(tǒng)一處理。其次,對于Hadoop中Hive和Pig這樣的腳本系統(tǒng)來說,使用代碼生成是不合理的。并且Protocol Buffers在序列化時考慮到數(shù)據(jù)定義與數(shù)據(jù)可能不完全匹配,在數(shù)據(jù)中添加注解,這會讓數(shù)據(jù)變得龐大并拖慢處理速度。其它序列化系統(tǒng)有如Protocol Buffers類似的問題。所以為了Hadoop的前途考慮,Doug Cutting主導(dǎo)開發(fā)一套全新的序列化系統(tǒng),這就是Avro,于09年加入Hadoop項目族中。

上面通過與Protocol Buffers的對比,大致清楚了Avro的特長。下面著重關(guān)注Avro的細節(jié)部分。

Avro依賴模式(Schema)來實現(xiàn)數(shù)據(jù)結(jié)構(gòu)定義??梢园涯J嚼斫鉃镴ava的類,它定義每個實例的結(jié)構(gòu),可以包含哪些屬性??梢愿鶕?jù)類來產(chǎn)生任意多個實例對象。對實例序列化操作時必須需要知道它的基本結(jié)構(gòu),也就需要參考類的信息。這里,根據(jù)模式產(chǎn)生的Avro對象類似于類的實例對象。每次序列化/反序列化時都需要知道模式的具體結(jié)構(gòu)。所以,在Avro可用的一些場景下,如文件存儲或是網(wǎng)絡(luò)通信,都需要模式與數(shù)據(jù)同時存在。Avro數(shù)據(jù)以模式來讀和寫(文件或是網(wǎng)絡(luò)),并且寫入的數(shù)據(jù)都不需要加入其它標(biāo)識,這樣序列化時速度快且結(jié)果內(nèi)容少。由于程序可以直接根據(jù)模式來處理數(shù)據(jù),所以Avro更適合于腳本語言的發(fā)揮。

Avro的模式主要由JSON對象來表示,它可能會有一些特定的屬性,用來描述某種類型(Type)的不同形式。Avro支持八種基本類型(Primitive Type)和六種混合類型(Complex Type)?;绢愋涂梢杂蒍SON字符串來表示。每種不同的混合類型有不同的屬性(Attribute)來定義,有些屬性是必須的,有些是可選的,如果需要的話,可以用JSON數(shù)組來存放多個JSON對象定義。在這幾種Avro定義的類型的支持下,可以由用戶來創(chuàng)造出豐富的數(shù)據(jù)結(jié)構(gòu)來,支持用戶紛繁復(fù)雜的數(shù)據(jù)。

Avro支持兩種序列化編碼方式:二進制編碼和JSON編碼。使用二進制編碼會高效序列化,并且序列化后得到的結(jié)果會比較小;而JSON一般用于調(diào)試系統(tǒng)或是基于WEB的應(yīng)用。對Avro數(shù)據(jù)序列化/反序列化時都需要對模式以深度優(yōu)先(Depth-First),從左到右(Left-to-Right)的遍歷順序來執(zhí)行?;绢愋偷男蛄谢菀捉鉀Q,混合類型的序列化會有很多不同規(guī)則。對于基本類型和混合類型的二進制編碼在文檔中規(guī)定,按照模式的解析順序依次排列字節(jié)。對于JSON編碼,聯(lián)合類型(Union Type)就與其它混合類型表現(xiàn)不一致。 Avro為了便于MapReduce的處理定義了一種容器文件格式(Container File Format)。這樣的文件中只能有一種模式,所有需要存入這個文件的對象都需要按照這種模式以二進制編碼的形式寫入。對象在文件中以塊(Block)來組織,并且這些對象都是可以被壓縮的。塊和塊之間會存在同步標(biāo)記符(Synchronization Marker),以便MapReduce方便地切割文件用于處理。下圖是根據(jù)文檔描述畫出的文件結(jié)構(gòu)圖:

點擊查看原始大小圖片

上圖已經(jīng)對各塊做肢解操作,但還是有必要再詳細說明下。一個存儲文件由兩部分組成:頭信息(Header)和數(shù)據(jù)塊(Data Block)。而頭信息又由三部分構(gòu)成:四個字節(jié)的前綴(類似于Magic Number),文件Meta-data信息和隨機生成的16字節(jié)同步標(biāo)記符。這里的Meta-data信息讓人有些疑惑,它除了文件的模式外,還能包含什么。文檔中指出當(dāng)前Avro認定的就兩個Meta-data:schema和codec。這里的codec表示對后面的文件數(shù)據(jù)塊(File Data Block)采用何種壓縮方式。Avro的實現(xiàn)都需要支持下面兩種壓縮方式:null(不壓縮)和deflate(使用Deflate算法壓縮數(shù)據(jù)塊)。除了文檔中認定的兩種Meta-data,用戶還可以自定義適用于自己的Meta-data。這里用long型來表示有多少個Meta-data數(shù)據(jù)對,也是讓用戶在實際應(yīng)用中可以定義足夠的Meta-data信息。對于每對Meta-data信息,都有一個string型的key(需要以“avro.”為前綴)和二進制編碼后的value。對于文件中頭信息之后的每個數(shù)據(jù)塊,有這樣的結(jié)構(gòu):一個long值記錄當(dāng)前塊有多少個對象,一個long值用于記錄當(dāng)前塊經(jīng)過壓縮后的字節(jié)數(shù),真正的序列化對象和16字節(jié)長度的同步標(biāo)記符。由于對象可以組織成不同的塊,使用時就可以不經(jīng)過反序列化而對某個數(shù)據(jù)塊進行操作。還可以由數(shù)據(jù)塊數(shù),對象數(shù)和同步標(biāo)記符來定位損壞的塊以確保數(shù)據(jù)完整性。

上面是將Avro對象序列化到文件的操作。與之相應(yīng)的,Avro也被作為一種RPC框架來使用??蛻舳讼M?wù)器端交互時,就需要交換雙方通信的協(xié)議,它類似于模式,需要雙方來定義,在Avro中被稱為消息(Message)。通信雙方都必須保持這種協(xié)議,以便于解析從對方發(fā)送過來的數(shù)據(jù),這也就是傳說中的握手階段。

消息從客戶端發(fā)送到服務(wù)器端需要經(jīng)過傳輸層(Transport Layer),它發(fā)送消息并接收服務(wù)器端的響應(yīng)。到達傳輸層的數(shù)據(jù)就是二進制數(shù)據(jù)。通常以HTTP作為傳輸模型,數(shù)據(jù)以POST方式發(fā)送到對方去。在Avro中,它的消息被封裝成為一組緩沖區(qū)(Buffer),類似于下圖的模型:

如上圖,每個緩沖區(qū)以四個字節(jié)開頭,中間是多個字節(jié)的緩沖數(shù)據(jù),最后以一個空緩沖區(qū)結(jié)尾。這種機制的好處在于,發(fā)送端在發(fā)送數(shù)據(jù)時可以很方便地組裝不同數(shù)據(jù)源的數(shù)據(jù),接收方也可以將數(shù)據(jù)存入不同的存儲區(qū)。還有,當(dāng)往緩沖區(qū)中寫數(shù)據(jù)時,大對象可以獨占一個緩沖區(qū),而不是與其它小對象混合存放,便于接收方方便地讀取大對象。

下面聊下Avro的其它方面信息。前文中引述Doug Cutting的話說,Protocol Buffer在傳輸數(shù)據(jù)時,往數(shù)據(jù)中加入注釋(annotation),以應(yīng)對數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)不匹配的問題。但直接導(dǎo)致數(shù)據(jù)量變大,解析困難等缺點。那Avro是如何應(yīng)對模式與數(shù)據(jù)的不同呢?為了保證Avro的高效,假定模式至少大部分是匹配的,然后定義一些驗證規(guī)則,如果在規(guī)則滿足的前提下,做數(shù)據(jù)驗證。如果模式不匹配就會報錯。相同模式,交互數(shù)據(jù)時,如果數(shù)據(jù)中缺少某個域(field),用規(guī)范中的默認值設(shè)置;如果數(shù)據(jù)中多了些與模式不匹配的數(shù)據(jù)。則忽視這些值。

Avro列出的優(yōu)點中還有一項是:可排序的。就是說,一種語言支持的Avro程序在序列化數(shù)據(jù)后,可由其它語言的Avro程序?qū)ξ捶葱蛄谢臄?shù)據(jù)排序。我不知道這種機制是在什么樣的場景下使用,但看起來還是挺不錯的。 當(dāng)前關(guān)于Avro的資料挺少的,上面的文章也是我由官方文檔和作者的文章來總結(jié)的。我相信其中肯定有很多錯誤,或許有些方面根本就理解錯了?,F(xiàn)在放出這篇總結(jié),便于不斷修訂和補充,也是對這兩天學(xué)習(xí)成果的分享,希望對想了解Avro的人有些許幫助,更希望大家指證我理解錯誤的地方,利于提高。

其它資料:
Avro規(guī)范:http://avro.apache.org/docs/current/spec.html
Doug Cutting文章:http://www.cloudera.com/blog/2009/11/avro-a-new-format-for-data-interchange/
各序列化系統(tǒng)性能比較:http://wiki.github.com/eishay/jvm-serializers/

最后編輯于
?著作權(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)容