­

ORC文件存儲格式的深入探究

  • 2020 年 2 月 10 日
  • 筆記

因為生病,另外還在做牙齒的根管治療,痛不欲生,短更一篇。

年前都在梳理《大數據成神之路》的目錄還有內容,另外Flink的公開課程也在規劃大綱和目錄。不知道我在說什麼,看一下這裡《2020年要做的幾件大事》。

昨天有個同學問了我一個問題。Hive中的文件存儲格式該選什麼?

然後在找到這個關於ORC的文章。如果你英文很好,參考這裡:

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC

一、ORC文件格式

ORC的全稱是(Optimized Record Columnar),使用ORC文件格式可以提高hive讀、寫和處理數據的能力。ORC在RCFile的基礎上進行了一定的改進,所以與RCFile相比,具有以下一些優勢: – 1、ORC中的特定的序列化與反序列化操作可以使ORC file writer根據數據類型進行寫出。 – 2、提供了多種RCFile中沒有的indexes,這些indexes可以使ORC的reader很快的讀到需要的數據,並且跳過無用數據,這使得ORC文件中的數據可以很快的得到訪問。 – 3、由於ORC file writer可以根據數據類型進行寫出,所以ORC可以支持複雜的數據結構(比如Map等)。 – 4、除了上面三個理論上就具有的優勢之外,ORC的具體實現上還有一些其他的優勢,比如ORC的stripe默認大小更大,為ORC writer提供了一個memory manager來管理內存使用情況。

圖1-ORC文件結構圖

二、ORC數據存儲方法

在ORC格式的hive表中,記錄首先會被橫向的切分為多個stripes,然後在每一個stripe內數據以列為單位進行存儲,所有列的內容都保存在同一個文件中。每個stripe的默認大小為256MB,相對於RCFile每個4MB的stripe而言,更大的stripe使ORC的數據讀取更加高效。 對於複雜數據類型,比如Map,ORC文件會將一個複雜數據類型字段解析成多個子字段。下表中列舉了ORC文件中對於複雜數據類型的解析

Data type

Chile columns

Array

一個包含所有數組元素的子字段

Map

兩個子字段,一個key字段,一個value字段

Struct

每一個屬性對應一個子字段

Union

每一個屬性對應一個子字段

當字段類型都被解析後,會由這些字段類型組成一個字段樹,只有樹的葉子節點才會保存表數據,這些葉子節點中的數據形成一個數據流,如上圖中的Data Stream。 為了使ORC文件的reader更加高效的讀取數據,字段的metadata會保存在Meta Stream中。在字段樹中,每一個非葉子節點記錄的就是字段的metadata,比如對一個array來說,會記錄它的長度。下圖根據表的字段類型生成了一個對應的字段樹。

在Hive-0.13中,ORC文件格式只支持讀取指定字段,還不支持只讀取特殊字段類型中的指定部分。 使用ORC文件格式時,用戶可以使用HDFS的每一個block存儲ORC文件的一個stripe。對於一個ORC文件來說,stripe的大小一般需要設置得比HDFS的block小,如果不這樣的話,一個stripe就會分別在HDFS的多個block上,當讀取這種數據時就會發生遠程讀數據的行為。如果設置stripe的只保存在一個block上的話,如果當前block上的剩餘空間不足以存儲下一個strpie,ORC的writer接下來會將數據打散保存在block剩餘的空間上,直到這個block存滿為止。這樣,下一個stripe又會從下一個block開始存儲。

三、索引

在ORC文件中添加索引是為了更加高效的從HDFS讀取數據。在ORC文件中使用的是稀疏索引(sparse indexes)。在ORC文件中主要有兩種用途的索引,一個是數據統計(Data Statistics)索引,一個是位置指針(Position Pointers)索引。

1. Data Statistics

ORC reader用這個索引來跳過讀取不必要的數據,在ORC writer生成ORC文件時會創建這個索引文件。這個索引中統計的信息主要有記錄的條數,記錄的max, min, sum值,以及對text類型和binary類型字段還會記錄其長度。對於複雜數據類型,比如Array, Map, Struct, Union,它們的子字段中也會記錄這些統計信息。 在ORC文件中,Data Statistics有三個level。 (1)file level statistics 在ORC文件的末尾會記錄文件級別的統計信息,會記錄整個文件中columns的統計信息。這些信息主要用於查詢的優化,也可以為一些簡單的聚合查詢比如max, min, sum輸出結果。 (2)stripe level statistics ORC文件會保存每個字段stripe級別的統計信息,ORC reader使用這些統計信息來確定對於一個查詢語句來說,需要讀入哪些stripe中的記錄。比如說某個stripe的字段max(a)=10,min(a)=3,那麼當where條件為a >10或者a <3時,那麼這個stripe中的所有記錄在查詢語句執行時不會被讀入。 (3)index group level statistics 為了進一步的避免讀入不必要的數據,在邏輯上將一個column的index以一個給定的值(默認為10000,可由參數配置)分割為多個index組。以10000條記錄為一個組,對數據進行統計。Hive查詢引擎會將where條件中的約束傳遞給ORC reader,這些reader根據組級別的統計信息,過濾掉不必要的數據。如果該值設置的太小,就會保存更多的統計信息,用戶需要根據自己數據的特點權衡一個合理的值。

3. Position Pointers

當讀取一個ORC文件時,ORC reader需要有兩個位置信息才能準確的進行數據讀取操作。 (1)metadata streams和data streams中每個group的開始位置 由於每個stripe中有多個group,ORC reader需要知道每個group的metadata streams和data streams的開始位置。圖1中右邊的虛線代表的就是這種pointer。 (2)stripes的開始位置 由於一個ORC文件可以包含多個stripes,並且一個HDFS block也能包含多個stripes。為了快速定位指定stripe的位置,需要知道每個stripe的開始位置。這些信息會保存在ORC file的File Footer中。如圖1中間位置的虛線所示。

四、文件壓縮

ORC文件使用兩級壓縮機制,首先將一個數據流使用流式編碼器進行編碼,然後使用一個可選的壓縮器對數據流進行進一步壓縮。 一個column可能保存在一個或多個數據流中,可以將數據流劃分為以下四種類型: • Byte Stream 位元組流保存一系列的位元組數據,不對數據進行編碼。 • Run Length Byte Stream 位元組長度位元組流保存一系列的位元組數據,對於相同的位元組,保存這個重複值以及該值在位元組流中出現的位置。 • Integer Stream 整形數據流保存一系列整形數據。可以對數據量進行位元組長度編碼以及delta編碼。具體使用哪種編碼方式需要根據整形流中的子序列模式來確定。 • Bit Field Stream 比特流主要用來保存boolean值組成的序列,一個位元組代表一個boolean值,在比特流的底層是用Run Length Byte Stream來實現的。 接下來會以Integer和String類型的字段舉例來說明。 (1)Integer 對於一個整形字段,會同時使用一個比特流和整形流。比特流用於標識某個值是否為null,整形流用於保存該整形字段非空記錄的整數值。 (2)String 對於一個String類型字段,ORC writer在開始時會檢查該字段值中不同的內容數占非空記錄總數的百分比不超過0.8的話,就使用字典編碼,字段值會保存在一個比特流,一個位元組流及兩個整形流中。比特流也是用於標識null值的,位元組流用於存儲字典值,一個整形流用於存儲字典中每個詞條的長度,另一個整形流用於記錄字段值。 如果不能用字典編碼,ORC writer會知道這個字段的重複值太少,用字典編碼效率不高,ORC writer會使用一個位元組流保存String字段的值,然後用一個整形流來保存每個字段的位元組長度。

在ORC文件中,在各種數據流的底層,用戶可以自選ZLIB, Snappy和LZO壓縮方式對數據流進行壓縮。編碼器一般會將一個數據流壓縮成一個個小的壓縮單元,在目前的實現中,壓縮單元的默認大小是256KB。

五、內存管理

當ORC writer寫數據時,會將整個stripe保存在內存中。由於stripe的默認值一般比較大,當有多個ORC writer同時寫數據時,可能會導致內存不足。為了現在這種並發寫時的內存消耗,ORC文件中引入了一個內存管理器。在一個Map或者Reduce任務中內存管理器會設置一個閾值,這個閾值會限制writer使用的總內存大小。當有新的writer需要寫出數據時,會向內存管理器註冊其大小(一般也就是stripe的大小),當內存管理器接收到的總註冊大小超過閾值時,內存管理器會將stripe的實際大小按該writer註冊的內存大小與總註冊內存大小的比例進行縮小。當有writer關閉時,內存管理器會將其註冊的內存從總註冊內存中註銷。

六、參數

參數名

默認值

說明

hive.exec.orc.default.stripe.size

256*1024*1024

stripe的默認大小

hive.exec.orc.default.block.size

256*1024*1024

orc文件在文件系統中的默認block大小,從hive-0.14開始

hive.exec.orc.dictionary.key.size.threshold

0.8

String類型字段使用字典編碼的閾值

hive.exec.orc.default.row.index.stride

10000

stripe中的分組大小

hive.exec.orc.default.compress

ZLIB

ORC文件的默認壓縮方式

hive.exec.orc.skip.corrupt.data

false

遇到錯誤數據的處理方式,false直接拋出異常,true則跳過該記錄

更多參數參考:https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties#ConfigurationProperties-ORCFileFormat