MaxCompute技術人背後的故事:從ApacheORC到AliORC
2019大資料技術公開課第一季《技術人生專訪》來襲,本季將帶領開發者們探討大資料技術,分享不同國家的工作體驗。本文整理自阿里巴巴計算平臺事業部高階技術專家吳剛的專訪,將為大家介紹Apache ORC開源專案、主流的開源列存格式ORC和Parquet的區別以及MaxCompute選擇ORC的原因。此外,吳還將分享他是如何一步步成為Apache開源專案的Committer和PMC的。
以下內容根據演講視訊以及PPT整理而成。
個人簡介
吳剛,阿里巴巴計算平臺事業部高階技術專家 ,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也專門用一頁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將檔案切分成大小相近的塊,在塊內部使用列式儲存,也就是將相同列的資料儲存到一起。針對於這些資料,ORC提供輕量的索引支援,包括資料塊的最小值、最大值、計數和空值等,基於這些統計資訊,可以非常方便地過濾掉不需要讀取的資料,以此減少資料的傳輸。此外,ORC還支援列裁剪 (Column Projection),如果查詢中只需要讀取部分列,那麼Reader只需要返回所需的列資料,進一步減小了需要讀取的資料量。
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 等,並且也使用了列式儲存和通用的壓縮以及編碼演算法,也能夠提供輕量級索引以及統計資訊。
相比ORC,Parquet主要有兩點不同。第一點就是Parquet能夠更好地支援巢狀型別,Parquet能夠通過使用definition和repetition levels方式來標識複雜型別的層數等資訊,不過這樣的設計卻非常複雜,就連Google的論文中也使用整整一頁來介紹這個演算法,但在實際中,大部分資料並沒有使用非常深的巢狀,這像是一個“殺雞用牛刀”的方法。此外,Parquet的編碼型別比ORC也更多一些,其支援plain、bit-packing以及浮點數等編碼方式,所以Parquet在某些資料型別的壓縮率上比ORC更高。
Benchmark: ORC VS Parquet
- 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開源的工作也代表了阿里巴巴對於開源的態度,不僅需要在數量上足夠多,還需要保證質量足夠好。
十、寄語
只要你對於開源感興趣並樂於持續地貢獻,無論擁有什麼樣的背景和基礎,所有的付出最終都會被認可。
本文作者:KB小祕書
本文為雲棲社群原創內容,未經