1. 程式人生 > 其它 >剛哥談架構(七)- 大資料系統的檔案儲存

剛哥談架構(七)- 大資料系統的檔案儲存

上一次我們談到了各種型別的資料庫,今天我們來談談在大資料,尤其是Hadoop棧下的資料和檔案的儲存。

我們知道為了解決大資料的儲存和處理問題,google最先設計了推出了Map/Reduce的演算法,而hadoop就是Google的map/reduce的開源實現。Hadoop主要由分散式的檔案系統HDFS(參考Google的GFS)和Map/Reduce計算這兩塊。但隨著Spark等更強大的計算引擎的出現,很少再有人使用Hadoop的Map/Reduce來做計算了,但是對於海量資料/檔案的儲存,除了HDFS,還真沒有更多更好的選擇。所以我們就來看看在Hadoop下,檔案儲存的各種選項。

原始文字檔案

首先,我們什麼都不需要做,HDFS提供分散式的檔案儲存,那麼我們就直接把原始的文字檔案儲存在HDFS上就好了。通常我們會使用諸如txt,csv,json,xml等文字格式的檔案儲存在HDFS上,然後由各種計算引擎載入,計算。

HDFS是按照塊來儲存檔案的,預設的設定一個塊的大小是64M,那麼假定我的文字檔案是1G,它會被分成16個分割槽,由計算引擎(Spark,Map/Reduce)來並行的處理,計算。

使用文字格式的主要問題是:

  • 佔用空間大
  • 處理時有額外的序列化反序列化的開銷,例如把日誌中的文字'12'轉化為數字的12

所以這裡就引入了兩個解決方案:

壓縮。壓縮是使用計算資源來換取儲存/IO的資源。因為壓縮後的體積小,儲存和傳輸的效率就變高了,當然,壓縮和解壓縮都會消耗系統的計算資源。常見的壓縮演算法有:snappy,gzip,bzip,LZO,zlib等

使用二進位制的序列化格式使用二進位制的序列化格式,本身就佔儲存空間比文字小,而且也有比較好的序列化和反序列化的支援。

支援壓縮的SequenceFile

為了解決文字檔案儲存和傳輸效率不高的問題,Hadoop提供了SequenceFile格式, SequenceFile是Hadoop API 提供的一種二進位制檔案, 它將資料(Key/Value形式)序列化到檔案中。這種二進位制檔案內部使用Hadoop 的標準的Writable 介面實現序列化和反序列化。 支援三種記錄儲存方式,無壓縮,記錄壓縮和塊壓縮。SequenceFile只支援Java, SequenceFile一般用來作為小檔案的容器使用, 防止小檔案佔用過多的NameNode記憶體空間來儲存其在DataNode位置的元資料。

語言無關的序列化檔案

SequenceFile雖然解決了本文檔案的空間佔用問題,但是它支援Java,而我們程式設計師都覺得PHP才是最好的語言,於是我們需要與語言無關的序列化檔案格式。Facebook推出了thrift,用於實現跨語言提供服務和介面, 滿足跨平臺通訊. 但是Thrift不支援分片, 且缺少MapReduce的原生支援。

Avro是一個語言無關的支援資料密集型的二進位制檔案格式和資料序列化的系統, 它的出現主要是為了解決Writables API缺少跨語言移植的缺陷。Avro將模式儲存在檔案頭中, 所以每個檔案都是自描述的, 而且Avro還支援模式演進(schema evolution), 也就是說, 讀取檔案的模式不需要與寫入檔案的模式嚴格匹配, 當有新需求時, 可以在模式中加入新的欄位。Avro的檔案格式更為緊湊,若要讀取大量資料時, Avro能夠提供更好的序列化和反序列化效能。Avro支援分片, 即使是進行Gzip壓縮之後。

Avro是Hadoop的基於行的儲存格式,已廣泛用作序列化平臺。Avro將模式Schema儲存為JSON格式,使任何程式均可輕鬆讀取和解釋。資料本身以二進位制格式儲存,從而使其緊湊高效。Avro是與語言無關的資料序列化系統。 它可以由多種語言(當前為C,C ++,C#,Java,Python和Ruby)處理。Avro的一項關鍵功能是對資料架構的強大支援,該架構會隨時間變化,即架構演變。 Avro處理架構更改,例如缺少欄位,新增的欄位和更改的欄位。Avro提供了豐富的資料結構。 例如,您可以建立一個包含陣列,列舉型別和子記錄的記錄。

這種格式是在資料湖著陸區中儲存資料的理想選擇,因為:1。 通常將從登陸區讀取的資料整體讀取,以供下游系統進行進一步處理(在這種情況下,基於行的格式更有效)2。 下游系統可以輕鬆地從檔案中檢索表模式(無需將Schema分別儲存在外部元儲存中)3。 任何源模式更改都易於處理(模式Schema演變)。

面向行/列的儲存格式

之前的檔案格式都是面向行的,同一行的資料儲存在一起,即連續儲存。採用這種方式,如果只需要訪問行的一小部分資料,亦需要將整行讀入記憶體,推遲序列化一定程度上可以緩解這個問題,但是從磁碟讀取整行資料的開銷卻無法避免。面向行的儲存適合於整行資料需要同時處理的情況。在大資料分析的場景下,我們常常對針對不同的列來做分析,大部分的分析計算,只會使用到少數的列,這個時候,行儲存的效率就不高了,因為會讀入並不需要的整行的資料。

為了解決行儲存對分析應用效率不高的問題,程式猿們發明了面向列的儲存格式。

RC檔案

Hive的Record Columnar File(記錄列檔案),這種型別的檔案首先將資料按行劃分為行組,然後在行組內部將資料儲存在列中。 它遵循"先按列劃分,再垂直劃分"的設計理念。當查詢過程中,針對它並不關心的列時,它會在IO上跳過這些列。需要說明的是,RCFile在map階段從 遠端拷貝仍然是拷貝整個資料塊,並且拷貝到本地目錄後RCFile並不是真正直接跳過不需要的列,並跳到需要讀取的列, 而是通過掃描每一個row group的頭部定義來實現的,但是在整個HDFS Block 級別的頭部並沒有定義每個列從哪個row group起始到哪個row group結束。所以在讀取所有列的情況下,RCFile的效能反而沒有SequenceFile高。它的結構如下:

ORC檔案

ORC是一種專為Hadoop工作負載設計的自我描述型別感知列式檔案格式。它針對大型流讀取進行了優化,但具有整合支援,可快速查詢所需的行。以列格式儲存資料使閱讀器僅可以讀取,解壓縮和處理當前查詢所需的值。由於ORC檔案可識別型別,因此編寫器為該型別選擇最合適的編碼,並在寫入檔案時建立內部索引。

ORC檔案格式提供了一種高效的資料儲存方式。 提供了比RCFile更有效的檔案格式。它旨在克服其他檔案格式的限制。 它理想地儲存緊湊的資料,並且無需大型,複雜或手動維護的索引就可以跳過不相關的部分。 ORC檔案格式解決了所有這些問題。

ORC檔案格式具有許多優點,例如:

  • 一個檔案作為每個任務的輸出,從而減輕了NameNode的負擔
  • 支援Hive型別,包括DateTime,十進位制和複雜型別(結構,列表,對映和聯合)
  • 使用單獨的RecordReader併發讀取同一檔案
  • 無需掃描標記即可分割檔案的能力
  • 根據檔案頁尾中的資訊,估計讀取器/寫入器在堆記憶體分配上的上限。
  • 使用協議緩衝區儲存的元資料,允許新增和刪除欄位

Parquet檔案

Apache Parquet是Hadoop生態系統中任何專案均可使用的列式儲存格式,而與資料處理框架,資料模型或程式語言的選擇無關。

Parquet的獨特功能之一是它也可以以列形式儲存具有巢狀結構的資料。 這意味著在Parquet檔案格式中,即使巢狀欄位也可以單獨讀取,而無需讀取巢狀結構中的所有欄位。 Parquet格式使用記錄粉碎和組裝演算法以列形式儲存巢狀結構。

要了解Hadoop中的Parquet檔案格式,您應該注意以下術語:

  • 行組:將資料邏輯地水平劃分為行。 行組由資料集中每個列的列塊組成。
  • 列塊:特定列的資料塊。 這些列塊位於特定的行組中,並保證在檔案中是連續的。
  • 頁面:列塊分為重新寫回的頁面。 這些頁面共享一個公共標題,讀應用可以跳過他們不感興趣的頁面。

Apache Arrow

Apache Arrow是用於記憶體資料的跨語言開發平臺。它為平面和分層資料指定了一種與語言無關的標準化列式儲存格式,該格式組織用於在現代硬體上進行有效的分析操作。它還提供計算庫和零複製流式訊息傳遞和程序間通訊。當前支援的語言包括C,C ++,C#,Go,Java,JavaScript,MATLAB,Python,R,Ruby和Rust。

簡而言之,它促進了許多元件之間的通訊,例如,使用Python Pandas 讀取Parquet檔案並轉換為Spark資料框,Falcon Data Visualization或Cassandra,而無需擔心轉換。

Apache Arrow利用列緩衝區來減少IO並加快分析處理效能。

如上圖所示,我們可以理解它是面向列的儲存,但是實在記憶體內實現的。它可以用於優化在計算系統之間的資料交換。

Apache CarbonData

Apache CarbonData是帶有多維索引的列式資料格式,用於在大資料平臺上進行快速分析。

CarbonData是華為開源,將使您能夠使用單個副本訪問整個資料。 查詢處理中的挑戰是我們有不同型別的查詢:

  • OLAP查詢和詳細查詢。
  • 大掃描查詢和小掃描查詢:您可能有需要比較大掃描的查詢,也可能有在較小區域內掃描的查詢。
  • 點查詢:消耗大表的很少部分。

因此,統一的檔案格式使您可以擁有不同型別的查詢(導致不同型別的資料訪問)。

CarbonData檔案格式是基於列式儲存的,並存儲在HDFS之上;其包含了現有列式儲存檔案格式的許多優點,比如:可分割、可壓縮、支援複雜資料型別等。CarbonData為了解決前面提到的幾點要求,加入了許多獨特的特性,主要概括為以下四點:(1)資料及索引:在有過濾的查詢中,它可以顯著地加速查詢效能,減少I/O和CPU資源;CarbonData的索引由多級索引組成,計算引擎可以利用這些索引資訊來減少排程和一些處理的開銷;掃描資料的時候可以僅僅掃描更細粒度的單元(稱為blocklet),而不再是掃描整個檔案;(2)可操作的編碼資料:通過支援高效的壓縮和全域性編碼模式,它可以直接在壓縮或者編碼的資料上查詢,僅僅在需要返回結果的時候才進行轉換,更好的查詢下推;(3)列組:支援列組,並且使用行格式進行儲存,減少查詢時行重建的開銷;(4)多種使用場景:順序存取、隨機訪問、類OLAP互動式查詢等。

一個CarbonData檔案是由一系列被稱為blocklet組成的,除了blocklet,還有許多其他的元資訊,比如模式、偏移量以及索引資訊等,這些元資訊是儲存在CarbonData檔案中的footer裡。當在記憶體中建立索引的時候都需要讀取footer裡面的資訊,因為可以利用這些資訊優化後續所有的查詢。

每個blocklet又是由許多Data Chunks組成。Data Chunks裡面的資料可以按列或者行的形式儲存;資料既可以是單獨的一列也可以是多列。檔案中所有blocklets都包含相同數量和型別的Data Chunks。CarbonData檔案格式如下圖所示。

每個Data Chunk又是由許多被稱為Pages的單元組成。總共有三種類型的pages:(1)Data Page:包含一列或者列組的編碼資料;(2)Row ID Page:包含行id的對映,在Data Page以反向索引的形式儲存時會被使用;(3)RLE Page:包含一些額外的元資訊,只有在Data Page使用RLE編碼的時候會被使用。

在一些給出的測試報告中,CarbonData的查詢效能要優與Parquet和Orc (作為列村格式一起比較)。

CarbonData的問題是它對於Spark的依賴比較重。

Apache Kudu

Apache Kudu是一種資料儲存技術,可以對快速資料進行快速分析。 Cloudera啟動了該專案,但它是完全開源的。 Kudu提供快速插入和更新功能以及快速搜尋功能,以加快分析速度。 它位於帶有Parquet的HBase和Impala之間,試圖消除快速掃描和快速隨機訪問之間的折衷。

我們直到列儲存對於分析優化,而HBase之類的資料庫是對隨機訪問優化,Kudu希望在這兩者中取得折衷,當然折衷的結果也可能是兩者都不是最優。

像傳統的關係資料庫模型一樣,Kudu需要在表上使用主鍵。 表具有列和原始資料型別,並支援更新。 如果要將關係資料庫遷移到Hadoop叢集,維護更新/刪除可能是一個挑戰。 這是由於"資料庫"工具直接位於HDFS之上。 由於HDFS是一次寫入的架構,因此更新行可能會很困難,因為您必須通過重寫基礎資料來複制此功能。

它不使用HDFS。 但是,它可以與HDFS在同一群集上共存。 您可以在Kudu常見問題解答頁面上找到做出此設計決定的多種原因。

每個表必須具有一個唯一的主鍵。 這充當索引,以允許快速訪問更新和刪除。 表由平板電腦組成,就像分割槽一樣。 平板電腦可跨多個節點複製,以實現彈性。 資料以列形式儲存。 這意味著由於每個列中的所有資料都按順序儲存,因此列式聚合更快。 這也意味著可以更輕鬆地對資料進行向量化和壓縮,因為每列的所有資料都是同一型別。

儘管Kudu位於HDFS之外,但它仍然是Hadoop叢集上的"好公民"。 它可以與HDFS節點共享資料磁碟,並且佔用的記憶體很少。 它還允許您透明地將Kudu表與Hadoop中其他位置(包括HBase表)儲存的資料連線在一起。

總結

在你的大資料應用中,檔案儲存是不可少的部分,如何選擇最適合的儲存格式是很重要的。

  • 為了節省儲存空間和I/O,你需要考慮支援壓縮和二進位制的序列化的格式,同時需要考慮是否有多語言的支援。這裡Avro是不錯的選擇。同時Avro是以行來儲存資料,適合要訪問整行的所有欄位的情況。Avro支援Schema,如果你的資料計劃有Schema的演進,Avro也是不錯的選擇。同時Avro和可以和流失計算例如Flink有很好的介面。同時行儲存格式適合密集寫的情況。
  • 為了更好的支援分析類的查詢,也就是說你通常不會訪問所有的欄位,這個時候可以考慮使用列儲存格式。例如Parquet,Orc。Parquet支援資料的巢狀,如果你的資料是巢狀格式的,Parquet比較適合。
  • 如果你希望在多中訪問模式,OLAP/全表掃描/詳細點查詢之間取得一定的權衡,可以考慮選擇CarbonData和Apache Kudu
  • Apache Arrow利用記憶體內的列儲存,能有效的在計算系統之間交換資料。

謝謝閱讀,歡迎和我交流相關的話題。