【摘要】2019大資料技術公開課第一季《技術人生專訪》來襲,本季将帶領開發者們探讨大資料技術,分享不同國家的工作體驗。本文整理自阿裡巴巴計算平台事業部進階技術專家吳剛的專訪,将為大家介紹Apache ORC開源項目、主流的開源列存格式ORC和Parquet的差別以及MaxCompute選擇ORC的原因。
以下内容根據演講視訊以及PPT整理而成。
PPT下載下傳位址:
https://102.alibaba.com/downloadFile.do?file=1566277715188/From%20Apache%20ORC%20to%20Ali%20ORC-min.pdf個人簡介
吳剛,阿裡巴巴計算平台事業部進階技術專家,Apache頂級開源項目ORC的PMC,目前主要負責MaxCompute平台存儲線相關工作。之前就職于Uber總部,從事Spark和Hive等相關工作。

一、Apache ORC項目介紹以及阿裡巴巴對于ORC項目的貢獻
Apache ORC Project
正如Apache ORC項目官網所介紹的,Apache ORC是Hadoop生态系統中最快、最小的列式存儲檔案格式。Apache ORC主打的三個特性包括支援ACID,也就是支援事務,支援内置索引以及支援各種複雜類型。
ORC Adopter
Apache ORC有很多的采用者,比如大家所熟知的Spark、Presto、Hive、Hadoop等開源軟體。此外,在2017年,阿裡巴巴MaxCompute技術團隊也開始參與到Apache ORC項目的工作中,并将ORC作為MaxCompute内置的檔案存儲格式之一。
Timeline
Apache ORC項目的大緻發展曆程如下圖所示。在2013年初的時候,Hortonworks開始來替代RCFile檔案格式,經過了兩個版本的疊代,ORC孵化成為了Apache頂級項目,并且順利地從Hive中脫離出來成為一個單獨的項目。在2017年1月,阿裡雲MaxCompute團隊開始向ORC社群持續地貢獻代碼,并且使得ORC成為MaxCompute内置的檔案格式之一。
Contribution from Alibaba
阿裡巴巴MaxCompute技術團隊為Apache ORC項目做出了大量貢獻,比如研發了一個完整的C++的ORC Writer,修複了一些極為重要的Bug,并且大大提升了ORC的性能。阿裡巴巴MaxCompute技術團隊總共向Apache ORC項目送出了30多個Patch,總計1萬5千多行代碼,并且目前阿裡仍然在持續地向ORC貢獻代碼。阿裡巴巴的技術團隊中共有3個ORC項目貢獻者,産生了 1個PMC和1個Committer。在2017年的Hadoop Summit上,ORC Owen O`Malley也專門用一頁PPT來點名表揚阿裡巴巴對于ORC項目的貢獻。
二、阿裡雲MaxCompute為何選擇ORC?
Row-based VS. Column-based
對于檔案存儲而言,有兩種主流的方式,即按行存儲以及按列存儲。所謂按行存儲就是把每一行資料依次存儲在一起,先存儲第一行的資料再存儲第二行的資料,以此類推。而所謂按列存儲就是把表中的資料按照列存儲在一起,先存儲第一列的資料,再存儲第二列的資料。而在大資料場景之下,往往隻需要擷取部分列的資料,那麼使用列存就可以隻讀取少量資料,這樣可以節省大量磁盤和網絡I/O的消耗。此外,因為相同列的資料屬性非常相似,備援度非常高,列式存儲可以增大資料壓縮率,進而大大節省磁盤空間。是以,MaxCompute最終選擇了列存。
A Quick Look at ORC
ORC在類型系統上的模組化是一個樹形結構,對于一些諸如Struct這樣的複雜類型會有一個或者多個孩子節點,而Map類型有兩個孩子節點,即key和value,List類型就隻有一個孩子節點,其他的普通類型則就是一個葉子節點。如下圖所示,左側的表結構就能夠被形象地轉化成右側的樹型結構,簡單并且直覺。
ORC的第二個優化名額就是存儲效率。ORC采用了通用的壓縮算法,比如開源的zStandard、zlib、snappy、LZO等來提高檔案壓縮率。同時,ORC也采用了輕量的編碼算法,比如run-length encoding、dictionary等。
How about Apache Parquet
在開源軟體領域中,與Apache ORC對标的就是Apache Parquet。Parquet是由Cloudera和Twitter共同開發的,其靈感來源于Google發表的Dremel的論文。Parquet的思想和ORC非常相近,也是将檔案拆分成大小相近的塊,并在塊裡面使用列式存儲,并且對于開源系統的支援與ORC也相差無幾,也能夠支援Spark、Presto等,并且也使用了列式存儲和通用的壓縮以及編碼算法,也能夠提供輕量級索引以及統計資訊。
-
Datasets
基于Github日志資料和紐約市計程車資料這兩個開源資料集,Hadoop開源社群進行了ORC和Parquet的性能對比,并得到了一些統計資料。
-
Storage Cost
下圖比較了ORC、Parquet以及JSON等檔案存儲方式的性能效率。在Taxi Size的這張表中可以看出,Parquet和ORC存儲性能非常相近。
下圖展示了Github項目資料集下的存儲效率比較,從中可以看出ORC比Parquet的壓縮率更高一些,壓縮後資料量變得更小。
是以,綜上所述,在存儲效率方面,ORC和Parquet壓縮效率不相上下,在部分資料上ORC優勢更大。
-
Full Table Scan
如下所示列出了ORC和Parquet對于兩個資料集的讀表效率對比情況。總體而言,ORC都比Parquet要更快一些。基于以上比較,MaxCompute最終選擇了ORC,因為其不僅設計更為簡單,并且讀表性能更高。
AliORC = Alibaba ORC
通過上述Benchmark的比較,MaxCompute基于對于性能的考量選擇了ORC。而在其他方面,相比于Parquet,ORC也有一些優勢,比如前面提到的設計更為簡單、代碼品質更佳、語言無關性 、能夠高效地支援多種開源項目。 并且由于ORC研發團隊相對更為集中,創始人對于項目具有較強的掌控力,是以阿裡巴巴提出的任何需求和想法都可以獲得快速響應和比較有力的支援,進而成為社群的上司者。
三、AliORC和開源ORC有何不同?
AliORC is More Than Apache ORC
AliORC是基于開源Apache ORC的深度優化的檔案格式。AliORC的首要目标還是和開源的ORC完全相容,這樣才能更加友善于使用者的使用。AliORC主要從兩個方面對于開源的ORC進行了優化,一方面,AliORC提供了更多的擴充特性,比如對于Clustered Index和C++ Arrow的支援以及謂詞下推等。另一方面,AliORC還進行了性能優化,實作了異步預讀、I/O模式管理以及自适應字典編碼等。
AliORC Optimization
-
Async Prefetch
這裡選取幾個AliORC對于開源的ORC優化的具體特性進行分享。首先就是Async Prefetch (異步預讀)。傳統讀檔案的方式一般是從底層檔案系統先拿到原始資料,然後進行解壓和解碼,這兩步操作分别是I/O密集型和CPU密集型任務,并且兩者沒有任何并行性,是以就加長了整體的端到端時間,但實際上并無必要,并且造成了資源的浪費。AliORC實作了從檔案系統讀資料和解壓解碼操作的并行處理,這樣就将所有的讀盤操作變成了異步的,也就是提前将讀取資料的請求全部發送出去,當真正需要資料的時候就去檢查之前的異步請求是否傳回了資料,如果資料已經傳回,則可以立即進行解壓和解碼操作,而不需要等待讀盤,這樣就可以極大地提高并行度,并降低讀取檔案的所需時間。
如下圖所示的就是打開了異步預讀優化前後的性能對比。開啟異步預讀之前,讀取一個檔案需要14秒,而在打開異步預讀之後則隻需要3秒,讀取速度提升了數倍。因為将所有的讀請求都變成了異步的,當異步請求傳回較慢時還是會變成同步請求。從右側餅圖可以看出,實際情況下80%以上的異步請求都是有效的。
-
Small I/O Elimination
AliORC的第二個優化點就是對于小I/O的消除。在ORC檔案中,不同列的檔案大小是完全不同的,但是每次讀盤都是以列為機關進行資料讀取的。這樣一來,對于資料量比較小的列而言,讀取時的網絡I/O開銷非常大。為了消除這些小的I/O開銷,AliORC在Writer部分針對不同列的資料量進行了排序,在reader端将小資料量的列放在一起形成一個大I/O塊,這樣不僅減少了小I/O數量,還大大地提升了并行度。
如下圖所示的是AliORC打開Small I/O Elimination前後的對比情況。藍色部分表示的就是打開Small I/O Elimination之前的I/O分布情況,橙色的部分則是表示打開之後的I/O分布情況。可以看到,打開Small I/O Elimination之前,小于64K的I/O有26個,而在打開之後,小于64K的I/O為零,是以Small I/O Elimination的優化效果還是非常顯著的。
- Memory Management for streams in each column
AliORC的第三個優化點就是在記憶體管理 。在開源版本的ORC實作中,Writer的每列資料都使用了一個很大的Buffer去儲存壓縮後的資料,預設大小為1M,其目的在于 Buffer設定得越大,壓縮率越高。但是正如前面所說的,不同列的資料量不同,某些列根本用不到1M大小的Buffer,是以就會造成極大的記憶體浪費。避免記憶體浪費的簡單方法就是在一開始的時候隻給很小的資料塊作為Buffer,并且按需配置設定,如果需要寫的資料更多,那麼就通過類似C++std::vector的resize 方式提供更大的資料塊。原本實作方式中,resize一次就需要進行一次O(N)的操作,将原始資料從老的Buffer拷貝到新的Buffer中去,這樣對于性能而言是不可接受的。是以,AliORC開發了新的記憶體管理結構,配置設定64K的Block,但是Block與Block之間不是連續的,這雖然會造成很多代碼的改動,但是這一改動卻是值得的。因為在很多場景下,原來的resize方式需要消耗很多記憶體,有可能造成記憶體耗盡,進而導緻任務無法完成,而新的方式可以在這種場景下大大降低記憶體的峰值,效果非常明顯。
- Seek Read
AliORC的第四個優化點就是Seek Read方面的優化。這部分解釋略微複雜,是以這裡以一個例子進行概括。Seek Read原來的問題在于壓縮塊比較大,每個壓縮塊中包含很多個Block。在圖中,每一萬行資料叫做一個Row Group。在Seek Read的場景下,可能會Seek Read到檔案中間的某一段,其可能是包含在某一個壓縮塊中間的,比如圖中第7個Row Group被包含在第2個Block中。正常Seek的操作就是先跳轉第2個Block的頭部,然後進行解壓,将第7個Row Group之前的資料先解壓出來,再真正地跳轉到第7個Row Group處。但是圖中綠色的部分資料并不是我們所需要的,是以這一段的資料量就被白白解壓了,浪費掉很多計算資源。是以,AliORC的想法就是就是【在寫檔案的時候】将壓縮塊Block和Row Group的邊界進行對齊,是以Seek到任何的Row Group都不需要進行不必要的解壓操作。
如圖所示的是進行Seek Read優化前後的效果對比。藍色部分是優化之前的情況,橙色部分代表優化之後的情況。可以發現,有了對于Seek Read的優化,解壓所需的時間和資料量都降低了5倍左右。
- Adapting Dictionary Encoding
字典編碼就是針對重複度比較高的字段首先整理出來一個字典,然後使用字典中的序号來代替原來的資料進行編碼,相當于将字元串類型資料的編碼轉化成整型資料的編碼,這樣可以大大減少資料量。但是ORC編碼存在一些問題,首先,不是所有的字元串都适合字典編碼,而在原來的資料中,每一列都是預設打開字典編碼的,而當檔案結束時再判斷列是否适合字典編碼,如果不适合,再回退到非字典編碼。由于回退操作相當于需要重寫字元串類型資料,是以開銷會非常大。AliORC所做的優化就是通過一個自适應的算法提早決定某一列是否需要使用字典編碼,這樣就可以節省很多的計算資源。開源的ORC中通過标準庫中的std::unordered_map來實作字典編碼,但是它的實作方式并不适合MaxCompute的資料,而Google開源的dense_hash_map庫可以帶來10%的寫性能提升,是以AliORC采用了這種實作方式。最後,開源的ORC标準中要求對于字典類型進行排序,但實際上是沒有任何必要的,剔除掉該限制可以使得Writer端的性能提高3%。
- Range Alignment for Range Partition
這部分主要是對于Range Partition的優化。如下圖右側的DDL所示,想要将一張表按照某些列進行RANGE CLUSTERED并對這些列的資料進行排序,比如将這些資料存儲到4個桶中,分别存儲0到1、2到3、4到8以及9到無窮大的資料。這樣做的優勢在于,在具體實作過程中,每個桶都使用了一個ORC檔案,在ORC檔案尾部存儲了一個類似于B+Tree的索引。當需要進行查詢的時候,如果查詢的Filter和Range Key相關,就可以直接利用該索引來排除不需要讀取的資料,進而大大減少所需要擷取的資料量。
對于Range Partition而言,AliORC具有一個很強大的功能,叫做Range對齊。這裡解釋一下,假設需要Join兩張Range Partition的表,它們的Join Key就是Range Partition Key。如下圖所示,表A有三個Range,表B有兩個Range。在普通表的情況下,這兩個表進行Join會産生大量的Shuffle,需要将相同的資料Shuffle到同一個Worker上進行Join操作,而Join操作又是非常消耗記憶體和CPU資源的。而有了Range Partition之後,就可以将Range的資訊進行對齊,将A表的三個桶和B表的兩個桶進行對齊,産生如下圖所示的三個藍色區間。之後就可以确定藍色區間之外的資料是不可能産生Join結果,是以Worker根本不需要讀取那些資料。
完成優化之後,每個Worker隻需要打開藍色區域的資料進行Join操作即可。這樣就可以使得Join操作能夠在本地Worker中完成,而不需要進行Shuffle,進而大大降低了資料傳輸量,提高了端到端的效率。
四、AliORC為使用者帶來的價值
如下圖所示的是在阿裡巴巴内部測試中AliORC和開源的C++版本ORC以及Java版本ORC的讀取時間比較。從圖中可以看出AliORC的讀取速度比開源ORC要快一倍。
截止2019年5月,在阿裡巴巴内部也疊代了3個版本,從下圖可以看出,每個版本之間也有接近30%的性能提升,并且還在持續優化當中。目前,AliORC還處于内部使用階段,尚未在公有雲上進行釋出,後續也會将AliORC開放出來,讓大家共享技術紅利。
五、淺談阿裡雲MaxCompute相比同類産品的優勢
首先,MaxCompute是開箱即用的,也就是說使用者無需額外的設定,直接啟動MaxCompute服務就可以在其上運作任務了。而使用Hive或者Spark等開源軟體可能會存在很多Bug,而對于問題的排查也異常困難,開源社群的修複周期也非常漫長。當使用者使用MaxCompute時遇到問題,能夠很快地得到回報并且完成修複。
其次,MaxCompute的使用成本比較低,可以實作按量付費。而使用Hive或者Spark往往需要自建資料中心,這樣的做法非常繁瑣,建設資料中心不僅需要支付機器成本,還需要自己進行運維。
再次,使用開源的Hive或者Spark,對于技術人員而言,門檻也比較高。因為需要招募一些非常了解Hive和Spark的工程師才能進行維護。而公司自己開發的一些特性往往會和開源版本産生沖突,每次都需要對于沖突進行解決。而當開源版本的軟體每次更新之後,就需要将新版本代碼下載下傳下來之後再将自己的開發的特性重新加進去,過程異常繁瑣。而使用MaxCompute之後,這些工作無需使用者關心,阿裡巴巴會幫助客戶處理這些問題。
對于穩定性而言,MaxCompute做的也非常好。其抗住了曆年雙11的流量洪峰,而直接使用Hadoop生态系統很難支援很大的體量的任務,往往需要各種深度定制優化。
MaxCompute另外一個優勢在于性能,MaxCompute是第一個跑過100TB資料量的TPCx-BB的Benchmark的平台,這是Spark至今沒有達到的成就。
此外,開源産品往往不夠重視中國市場。Cloudera、Databricks等公司的主要目标客戶還是在美國,往往更傾向于根據美國客戶需求進行開發,而對于中國市場的支援不夠好。MaxCompute則緊跟中國客戶的需要,同時也更加适合中國市場。
最後一點就是隻有在MaxCompute裡面才能使用AliORC這樣的檔案格式,這也是獨有的優勢。
總結而言,相比于開源軟體,MaxCompute具有需求響應更加及時、成本更低、技術門檻更低、穩定性更高、性能更好、更加适合中國市場等特性。
六、為何選擇加入MaxCompute團隊
從個人角度而言,我更加看好大資料領域。雖然對于一項技術而言,黃金期往往隻有10年,而對于大資料技術而言,已經經曆了10年,但我相信大資料技術并不會衰落。尤其是在人工智能技術的加持下,大資料技術仍然有很多需要解決的問題,其技術仍然沒有達到的完美。此外,阿裡的MaxCompute團隊更是人才濟濟,北京、杭州、西雅圖等團隊都具有強大的技術實力,能夠學習到很多。最後一點,對于開源大資料産品而言,基本上都是國外的天下,而MaxCompute是完全國産自研的平台,加入MaxCompute團隊讓自己非常驕傲,能夠有機會為國産軟體盡一份力量。
七、如何走上大資料技術之路的
我走上大資料技術這條路也是機緣巧合的,之前在學校裡面所學習的内容與大資料完全沒有關系,第一份工作也是視訊編碼相關的工作,後來在Uber轉向大資料相關的崗位。在進入Uber之前,Hadoop組還處于組建的早期,基本上還沒有人真正使用Hadoop,大家都是自己搭建一些服務來運作任務。當進入Uber的Hadoop組之後,跟着團隊從0到1地學習了Scala、Spark等,從最開始了解如何使用Spark到了解Spark源碼,然後慢慢地搭建起大資料平台,接觸大資料領域。進入阿裡巴巴之後,通過MaxCompute能夠從需求、設計、開發、測試以及最後的優化等全部階段來了解大資料産品,這也是比較寶貴的經曆。
八、在阿裡巴巴美國辦公室的工作體驗
在阿裡的美國部門其實和在阿裡國内的部門差别并不大,可能在西雅圖的辦公室人數并不是很多,但是“麻雀雖小,五髒俱全”。西雅圖辦公室各個BU的成員都非常優秀,能夠和不同技術方向的同僚碰撞出不同的思維火花。并且在阿裡巴巴的美國辦公室,每年有很多對外交流的機會,也可以組織很多開源的分享。
九、如何成為第一位華人ORC的PMC
這其實是因為MaxCompute團隊需要ORC這款産品,而當時開源的C++版本的ORC隻有Reader,卻沒有Writer,是以就需要自行開發C++版本的ORC的Writer。當MaxCompute團隊完成之後就希望集合開源的力量将C++版本的ORC的Writer做好,是以将代碼貢獻回了開源社群,并且得到了開源社群的認可。基于這些工作量,ORC的開源社群給了MaxCompute團隊兩個Committer名額。成為Committer之後,責任也就更大了,不僅自己需要寫代碼,還需要和社群一起成長,review其他成員的代碼,讨論短期和長期的問題。ORC社群對于自己和MaxCompute團隊的工作較為認可,是以授予了PMC的職位。對個人而言,ORC開源的工作也代表了阿裡巴巴對于開源的态度,不僅需要在數量上足夠多,還需要保證品質足夠好。
十、寄語
隻要你對于開源感興趣并樂于持續地貢獻,無論擁有什麼樣的背景和基礎,所有的付出最終都會被認可。
歡迎加入“MaxCompute開發者社群2群”,點選連結申請加入或掃描二維碼
https://h5.dingtalk.com/invite-page/index.html?bizSource=____source____&corpId=dingb682fb31ec15e09f35c2f4657eb6378f&inviterUid=E3F28CD2308408A8&encodeDeptId=0054DC2B53AFE745