Hive優化_1. 資料檔案優化篇
之前轉載了一篇<Hive - 資料倉庫的效能優化>。博主總結的很不錯。這裡本人將自己平時積累的資料彙總了一下,來補充一下這篇文章:
針對方法上篇的優化方法1,2,3 主要建立在 Hive 觸發了一個 MapReduce Job。但是我們都知道,啟用 MapReduce Job 會消耗系統開銷的(從我這篇博文 Hive_4.DDL
-- 資料庫&內部表&外部表 可以發現當使用 Like 關鍵詞的時候效率比 CTAS 要快很多倍)。對於這個問題, Hive 從0.10.0 版本開始,對於簡單的不需要聚合操作的語句將不會觸發 MapReduce Job,直接通過 Fetch task 來獲取資料。
詳細資訊可以參考:
1. 資料檔案優化:
資料檔案的優化包含了通過資料檔案格式, 壓縮,儲存方式的選擇來進行效能提升。
Hive 最新發布的 0.14.0 版本中支援TEXTFILE
, SEQUENCEFILE
, RCFILE
, ORC
, PARQUET 和 Avro檔案格式。我們可以通過以下方法來指定檔案的格式:
CREATE TABLE ... STORE AS <File_Format>
ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT <File_Format>
SET hive.default.fileformat = <File_Format> --設定表的預設檔案格式
在這裡,<File_Type>
可以是 TEXTFILE
, SEQUENCEFILE
, RCFILE
, ORC
, PARQUET
或者
Avro
型別
.
我們可以通過 TEXTFILE
格式將 text 檔案直接載入到一張表中。如果要往表中載入其他格式的資料,我們需要將資料先載入成 TEXTFILE
格式的表,之後再使用 INSERT
OVERWRITE TABLE <target_file_format_table> SELECT * FROM <text_format_source_table>
Hive 支援如下資料格式,它們的優化如下所示:
- TEXTFILE :這是 Hive 預設的檔案格式。文字檔案中的資料沒有被壓縮,所以我們可以通過壓縮工具( GZip, Bzip2, Snappy) 對它進行壓縮。但是 Gzip 和 Snappy 壓縮的檔案是不可分割的,這就導致了處理一個大檔案時需要一個單獨的,耗資源的 map job 。增加了系統的負擔和時間。這裡需要注意的是,Bzip2 從 Hadoop 2.1 開始才支援本地可分割。所以你會發現網上很多文章都把 Bzip2 認為是不可分割的。我將會在之後的 Hadoop Compression 專題中詳
- SEQUENCEFILE:這是一個基於鍵值對的二進位制儲存格式。它是優勢是 SequenceFile 比文字檔案更加緊湊,同時能夠很好的相容 MapReduce 的輸出格式。SequenceFile 有3中壓縮方式:Record & Block & Null。 你可以通過以下方式來啟動 Blcok 級別的壓縮:
jdbc:hive2://> SET hive.exec.compress.output=true; jdbc:hive2://> SET io.seqfile.compression.type=BLOCK;不幸的是,文字檔案和 SequenceFile 都是基於行級別的儲存檔案格式,對Hive 來說並不是最優的選擇。由於 Hive 每次都需要讀取整行資料,儘管只需要一列資料。因此 RCFile , ORC, Parquet 便應運而生了。它們用來解決文字檔案和 SequenceFile所存在的限制。(這裡需要了解一下 Avro 也是基於行的儲存,由於在 Avro 系列中已經做了詳細介紹,這裡就不對 Avro 過多闡述了)
- RCFile :它是柱狀記錄檔案(Record Columnar File)的簡稱。它是一個由二進位制鍵值對組成的平面檔案,與SequenceFile 有點相似。RCFile 是基於行組(row group)的水平資料分割。這裡一個或者多個行組是 HDFS 中儲存的檔案。RCFile 通過首先將每一行的第一列來將行組資料儲存為柱狀格式,之後再對每一行的第二列,。。。這種格式是可分割的並且允許 Hive 跳過無關資料來更快更輕鬆得到資料結果。
- ORC :它是Optimized
Row Columnar的簡寫。從 Hive 0.11.0 版本才開始支援 ORC 格式。ORC 用來解決 RCFile部分效能問題。它提供了預設的 256MB 大小的 blcok ( RCFile 是 4MB, SequenceFile 是1MB)來對NameNode
節點上的高吞吐量和通過更少的 reducer端需要處理的檔案來優化HDFS 中序列化檔案的讀取。與 RCFile 不同的是,ORC 需要依賴元資料來確認資料型別。它通過特定的編碼器來識別資料型別,這樣它就能根據不同型別進行壓縮優化。ORC 同樣支援基本列的統計方法:
MIN
,MAX
,SUM
, 和COUNT
.以及使用一個輕量級的索引來跳過無關的行塊。
- Parquet :它是一個類似於 ORC 格式的行柱狀檔案格式。不同的是,相比較只支援 Hive 和 Pig 的ORC 格式,Parquet 在 Hadoop 生態系統中已經廣泛支援許多專案。Parquet 利用 Google的最佳實踐案例:Dremel 來支援巢狀的結構化資料。Parquet 支援從 Hive 0.10.0 版本開始就可以作為一個外掛進行使用,知道 Hive 0.13.0 才開始得到本地支援。(Avro 是從 Hive 0.14 版本才得到本地支援)。
Google Dremel 原理(中文):http://www.yankay.com/google-dremel-rationale/
考慮到 Hive 的成熟度,還是建議在你的 Hadoop 環境中使用 ORC 格式作為主要的工具。如果你的 Hadoop 生態系統中使用多種 tools, Parquet 在適應性方面不失為一個更好的選擇。
注意:Hadoop Archive File (HAR) 是HDFS 中另一種打包檔案的格式。它對HDFS中大量的小檔案儲存是可選的(並不是很好的選擇)。由於將大量的小檔案直接儲存是非常低效的。HAR 目前仍然有以下的一些限制使得它無法出眾:不可分割,相容性比較差。更多關於 HAR 資訊請參考維基百科:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Archiving.
1.2 壓縮
為 Mapper 和 Reducer 中間資料和HDFS結果資料選擇合適的壓縮格式,在Hive 中能夠明顯的減小磁碟的 I/O,以至於Hive 查詢也會有更好的效能。為了對 Hive 通過 MapReduce job 處理的檔案進行壓縮,我們需要通過 Hive CLI 或者 hive-site.xml
檔案來設定以下屬性(預設情況是 false
):
jdbc:hive2://> SET hive.exec.compress.intermediate=true
接下來,我們就需要考慮應該配置哪一種壓縮編碼,Hadoop 和 Hive 中支援的通用壓縮編碼器如下所示:
壓縮方式 |
編碼方式 |
拓展名 |
可分割 |
---|---|---|---|
Deflate |
org.apache.hadoop.io.compress.DefaultCodec |
|
N |
GZip |
org.apache.hadoop.io.compress.GzipCodec |
|
N |
Bzip2 |
org.apache.hadoop.io.compress.BZip2Codec |
|
Y |
LZO |
com.hadoop.compression.lzo.LzopCodec |
|
N |
LZ4 |
org.apache.hadoop.io.compress.Lz4Codec |
|
N |
Snappy |
org.apache.hadoop.io.compress.SnappyCodec |
|
N |
Hadoop 有一個預設壓縮編碼器(.deflate
),壓縮率和
CPU 成本都比 GZip 要高。Bzip2 是可分割的,但是直到 Hadoop 1.1 才支援分割(參考 Jira ticket :https://issues.apache.org/jira/browse/HADOOP-4012)。Bzip2
也由於高額的 CUP 開銷使得壓縮很緩慢。
LZO 檔案並不是本地可分割,但是我們可以通過 com.hadoop.compression.lzo.LzoIndexer 建立一個索引來決定檔案的分割,它很好的中和了CUP開銷和壓縮率(在後面會有專題介紹該內容)。LZ4
和 Snappy能夠很好的處理一個 Job。
由於很多編碼方法不支援壓縮後可分割,所以不建議在 HDFS 中壓縮大檔案。
你可以通過 mapred-site.xml
, hive-site.xml
或者
Hive CLI 來指定壓縮編碼器,如下所示:
jdbc:hive2://> SET hive.intermediate.compression.codec=
. . . . . . .> org.apache.hadoop.io.compress.SnappyCodec
對指定的 Job 中間資料的壓縮只會節省磁碟空間,但是需要多個 map 和 reduce job。為了進一步節省磁碟空間,Hive 的輸出檔案是可以被壓縮的。可以通過設定 hive.exec.compress.output
屬性為 true.
Hive 可以通過配置 mapred.map.output.compression.codec 屬性來對中間資料進行壓縮。你可以從hive-site.xml
檔案進行設定,或者在
Hive CLI 設定。
jdbc:hive2://> SET hive.exec.compress.output=truejdbc:hive2://> SET mapred.output.compression.codec=
. . . . . . .> org.apache.hadoop.io.compress.SnappyCodec
1.3 儲存優化
對於頻繁用於掃描的資料,我們會稱之為 Hot data。通常,對於hot data 的查詢對整體效能來說是至關重要的。增加 hot data 在 HDFS 中的副本因子可以增加Hive job 本地查詢命中率並且能夠提高效能。這同樣是衡量儲存的一個方面:
$ hdfs dfs -setrep -R -w 4 /user/hive/warehouse/employeeReplication 4 set: /user/hive/warehouse/employee/000000_0
另一方面,太多的檔案或者冗餘會耗盡NameNode 的記憶體,特別的對於大量的小於 Hadoop blcok 大小的檔案。Hadoop 對於處理大量小檔案問題的這種情況已經提出瞭解決方案。如下所示:
- Hadoop Archive and HAR:用來打包小檔案的工具集.
- SequenceFile format : 將小檔案壓縮成大檔案的一種格式.
- CombineFileInputFormat : 一種在map
和 reduce 程序前整合小檔案的輸入格式。是 Hive 的預設
InputFormat
( 參考:https://issues.apache.org/jira/browse/HIVE-2245)。 - HDFS federation :它允許 NameNode 有更好的擴充套件性並且能夠管理多個檔案。
我們同樣可以使用 Hadoop 生態系統中的其他工具來處理(在已經安裝該工具的前提下),如下所示:
- HBase 有更小的 block 大小和檔案格式來處理小檔案處理問題。
- 通過離線的檔案整合程式來將 HDFS 中小檔案整合到一起。
對 Hive 來說,我們可以通過配置屬性來將查詢結果進行整合,避免建立小檔案:
hive.merge.mapfiles
: 將在只有 map 的job 中整合小檔案,預設為true
.hive.merge.mapredfiles
: 在 MapReduce Job 最後進行整合小檔案,可以設定為true
, 預設是false
.hive.merge.size.per.task
: 該屬性定義了對於每個任務執行整合的檔案最大值。預設是 256,000,000.hive.merge.smallfiles.avgsize
: 這是用來觸發檔案整合操作的閾值,預設是16,000,000.
當輸出檔案的平均大學都小於指定的 hive.merge.smallfiles.avgsize
值,並且hive.merge.mapfiles 和 hive.merge.mapredfiles 都設定為true,Hive
會啟動一個額外的 MapReduce Job 來整合輸出檔案為一個大檔案。