1. 程式人生 > >csv、parquet、orc讀寫效能和方式

csv、parquet、orc讀寫效能和方式

背景


     最近在做一個大資料分析平臺的專案,專案開發過程中使用spark來計算工作流工程中的每一個計算步驟,多個spark submit計算提交,構成了一個工作流程的計算。其中使用csv來作為多個計算步驟之間的中間結果儲存檔案,但是csv作為毫無壓縮的文字儲存方式顯然有些效能不夠,所以想要尋找一個儲存檔案效率更高或者執行效率更高的檔案格式作為替代品。

 

儲存方式
    csv


            csv資料檔案屬於文字儲存方式,spark預設支援,按照行以文字的方式寫到檔案中,每行一條記錄.一般來說文字儲存方式無壓縮,效能相對較差。

    parquet           
              Apache Parquet是Hadoop生態圈中一種新型列式儲存格式,它可以相容Hadoop生態圈中大多數計算框架(Mapreduce、Spark等),被多種查詢引擎支援(Hive、Impala、Drill等),並且它是語言和平臺無關的。Parquet最初是由Twitter和Cloudera合作開發完成並開源,2015年5月從Apache的孵化器裡畢業成為Apache頂級專案。

              Parquet最初的靈感來自Google於2010年發表的Dremel論文,文中介紹了一種支援巢狀結構的儲存格式,並且使用了列式儲存的方式提升查詢效能,在Dremel論文中還介紹了Google如何使用這種儲存格式實現並行查詢的,如果對此感興趣可以參考論文和開源實現Drill。

           
             Parquet檔案是以二進位制方式儲存的,是不可以直接讀取和修改的,Parquet檔案是自解析的,檔案中包括該檔案的資料和元資料。在HDFS檔案系統和Parquet檔案中存在如下幾個概念:

HDFS塊(Block):它是HDFS上的最小的副本單位,HDFS會把一個Block儲存在本地的一個檔案並且維護分散在不同的機器上的多個副本,通常情況下一個Block的大小為256M、512M等。
HDFS檔案(File):一個HDFS的檔案,包括資料和元資料,資料分散儲存在多個Block中。
行組(Row Group):按照行將資料物理上劃分為多個單元,每一個行組包含一定的行數,在一個HDFS檔案中至少儲存一個行組,Parquet讀寫的時候會將整個行組快取在記憶體中,所以如果每一個行組的大小是由記憶體大的小決定的。
列塊(Column Chunk):在一個行組中每一列儲存在一個列塊中,行組中的所有列連續的儲存在這個行組檔案中。不同的列塊可能使用不同的演算法進行壓縮。
頁(Page):每一個列塊劃分為多個頁,一個頁是最小的編碼的單位,在同一個列塊的不同頁可能使用不同的編碼方式。
              通常情況下,在儲存Parquet資料的時候會按照HDFS的Block大小設定行組的大小,由於一般情況下每一個Mapper任務處理資料的最小單位是一個Block,這樣可以把每一個行組由一個Mapper任務處理,增大任務執行並行度。Parquet檔案的格式如下圖所示。

可以看出,儲存格式中元資料索引資訊是被儲存在最後的,所以當讀取某一行的資料的時候,就需要去定位最後的索引資訊,最後才能去讀取對應的行資料。   

 orc


             ORC檔案格式是一種Hadoop生態圈中的列式儲存格式,它的產生早在2013年初,最初產生自Apache Hive,用於降低Hadoop資料儲存空間和加速Hive查詢速度。和Parquet類似,它並不是一個單純的列式儲存格式,仍然是首先根據行組分割整個表,在每一個行組內進行按列儲存。ORC檔案是自描述的,它的元資料使用Protocol Buffers序列化,並且檔案中的資料儘可能的壓縮以降低儲存空間的消耗,目前也被Spark SQL、Presto等查詢引擎支援,但是Impala對於ORC目前沒有支援,仍然使用Parquet作為主要的列式儲存格式。2015年ORC專案被Apache專案基金會提升為Apache頂級專案。
              和Parquet類似,ORC檔案也是以二進位制方式儲存的,所以是不可以直接讀取,ORC檔案也是自解析的,它包含許多的元資料,這些元資料都是同構ProtoBuffer進行序列化的。ORC的檔案結構入圖6,其中涉及到如下的概念:

ORC檔案:儲存在檔案系統上的普通二進位制檔案,一個ORC檔案中可以包含多個stripe,每一個stripe包含多條記錄,這些記錄按照列進行獨立儲存,對應到Parquet中的row group的概念。
檔案級元資料:包括檔案的描述資訊PostScript、檔案meta資訊(包括整個檔案的統計資訊)、所有stripe的資訊和檔案schema資訊。
stripe:一組行形成一個stripe,每次讀取檔案是以行組為單位的,一般為HDFS的塊大小,儲存了每一列的索引和資料。
stripe元資料:儲存stripe的位置、每一個列的在該stripe的統計資訊以及所有的stream型別和位置。
row group:索引的最小單位,一個stripe中包含多個row group,預設為10000個值組成。
stream:一個stream表示檔案中一段有效的資料,包括索引和資料兩類。索引stream儲存每一個row group的位置和統計資訊,資料stream包括多種型別的資料,具體需要哪幾種是由該列型別和編碼方式決定。
ORCæ件ç»æ

 和parquet不同的是,每一個row data的開始,都會有index data索引資訊,相對於parquet把索引資訊放在最後而言,理論上行讀取的速度要更快一點。

儲存大小(儲存效率)

原始資料:

     size:64G/format:csv/location:hdfs

叢集執行環境:

     5臺/記憶體:24G/核心:16核

資料相同,從csv轉換成了如下不同格式,讀寫效率如下:

格式     大小 讀寫時間 count操作一次時間
csv 36G 3.6min 59s
parquet 6G 1.1min 5s
orc 5.9G 1.2min 5s
avro 13G 1.3min 25s

 

    size:可以看出,相對於csv而言,parque和orc直接縮小了6倍的大小,理論上說可以達到6-10倍的壓縮效率,本次使用的parquet預設的gzip壓縮方式。

    time:更值得注意的一點是,針對count這種列操作的方法,parquet、orc和avro都獲得了相當好的效果,猜測可能是因為不需要這個資料集來計算,而僅僅使用某一些列就能計算,減小了計算的規模。

讀寫程式碼


  1.csv太普遍了這裡就省略了

  2.parquet:

val df  = sc.read.parquet("path")
df.write.format("parquet").save("hdfs path")

  3.orc:

val df = sc.read.orc("path")
df.write.format("orc").save("hdfs path")


 4.avro:

var data = sc.read.format("com.databricks.spark.avro")
    .option("header", "true")
    .option("mode", "DROPMALFORMED")
    .option("delimiter", ",")
    .load("hdfs://192.168.10.10:9000/data/test/Solderc_to_c.csv")
 
df.write.format("com.databricks.spark.avro").save("hdfs path")


 avro可是使用databricks進行讀取,當然比忘了新增databricks的maven依賴

結論


       csv使用較為廣泛,多數系統的輸入都是csv格式,此外csv檔案直接開啟是可以理解和讀懂的,而且csv檔案也是支援末尾新增資料的,但是csv檔案因為沒有壓縮,所以體積較大,某些操作上也不如列式儲存。

       parquet使用也較為廣泛,預設使用gzip壓縮,體積較,運算效率高,但是parquet開啟是不能被理解和讀懂的,因為其採用二進位制儲存方式,當系統中無特殊要求,也去需要開啟資料檔案的時候,為了追求效率可以考慮。

      orc也是列示儲存的二進位制檔案,開啟無法被直接理解和讀懂,但是因為在檔案格式中,每一個row block的開始都有一個輕型索引,所以相較於parquet,orc在檢索行的時候,速度要相對較快一點,

其他格式
還有其他的一些格式:indexR/ya100

引用文章如下:

http://blog.csdn.net/yu616568/article/details/51868447

https://www.cnblogs.com/piaolingzxh/p/5469964.html