當前位置:編程學習大全網 - 源碼下載 - 使用Hive SQL插入動態分區的Parquet表OOM異常分析

使用Hive SQL插入動態分區的Parquet表OOM異常分析

1.異常描述

當運行“INSERT ... SELECT”語句向 Parquet 或者 ORC 格式的表中插入數據時,如果啟用了動態分區,妳可能會碰到以下錯誤,而導致作業無法正常執行。

Hive 客戶端:

(可左右滑動)

YARN 的 8088 中查看具體 map task 報錯:

(可左右滑動)

2.異常分析

Parquet 和 ORC 是列式批處理文件格式。這些格式要求在寫入文件之前將批次的行(batches of rows)緩存在內存中。在執行 INSERT 語句時,動態分區目前的實現是:至少為每個動態分區目錄打開壹個文件寫入器(file writer)。由於這些緩沖區是按分區維護的,因此在運行時所需的內存量隨著分區數量的增加而增加。所以經常會導致 mappers 或 reducers 的 OOM,具體取決於打開的文件寫入器(file writer)的數量。

通過 INSERT 語句插入數據到動態分區表中,也可能會超過 HDFS 同時打開文件數的限制。

如果沒有 join 或聚合,INSERT ... SELECT 語句會被轉換為只有 map 任務的作業。mapper 任務會讀取輸入記錄然後將它們發送到目標分區目錄。在這種情況下,每個 mapper 必須為遇到的每個動態分區創建壹個新的文件寫入器(file writer)。mapper 在運行時所需的內存量隨著它遇到的分區數量的增加而增加。

3.異常重現與解決

3.1.生成動態分區的幾個參數說明

hive.exec.dynamic.partition

默認值:false

是否開啟動態分區功能,默認 false 關閉。

使用動態分區時候,該參數必須設置成 true;

hive.exec.dynamic.partition.mode

默認值:strict

動態分區的模式,默認 strict,表示必須指定至少壹個分區為靜態分區,nonstrict 模式表示允許所有的分區字段都可以使用動態分區。

壹般需要設置為 nonstrict

hive.exec.max.dynamic.partitions.pernode

默認值:100

在每個執行 MR 的節點上,最大可以創建多少個動態分區。

該參數需要根據實際的數據來設定。

比如:源數據中包含了壹年的數據,即 day 字段有 365 個值,那麽該參數就需要設置成大於 365,如果使用默認值 100,則會報錯。

hive.exec.max.dynamic.partitions

默認值:1000

在所有執行 MR 的節點上,最大壹***可以創建多少個動態分區。

同上參數解釋。

hive.exec.max.created.files

默認值:100000

整個 MR Job 中,最大可以創建多少個 HDFS 文件。

壹般默認值足夠了,除非妳的數據量非常大,需要創建的文件數大於 100000,可根據實際情況加以調整。

mapreduce.map.memory.mb

map 任務的物理內存分配值,常見設置為 1GB,2GB,4GB 等。

mapreduce.map.java.opts

map 任務的 Java 堆棧大小設置,壹般設置為小於等於上面那個值的 75%,這樣可以保證 map 任務有足夠的堆棧外內存空間。

mapreduce.input.fileinputformat.split.maxsize

mapreduce.input.fileinputformat.split.minsize

這個兩個參數聯合起來用,主要是為了方便控制 mapreduce 的 map 數量。比如我設置為 1073741824,就是為了讓每個 map 處理 1GB 的文件。

3.2.壹個例子

Fayson 在前兩天給人調壹個使用 Hive SQL 插入動態分區的 Parquet 表時,總是報錯 OOM,也是折騰了很久。以下我們來看看整個過程。

1.首先我們看看執行腳本的內容,基本其實就是使用 Hive 的 insert 語句將文本數據表插入到另外壹張 parquet 表中,當然使用了動態分區。

2.我們看看原始數據文件,是文本文件,壹*** 120 個,每個 30GB 大小,總***差不多 3.6TB。

3.我們看看報錯

4.因為是壹個只有 map 的 mapreduce 任務,當我們從 YARN 的 8088 觀察這個作業時可以發現,基本沒有壹個 map 能夠執行成功,全部都是失敗的。報上面的錯誤。

5.把 mapreduce.map.memory.mb 從 2GB 增大到 4GB,8GB,16GB,相應 mapreduce.map.java.opts 增大到 3GB,6GB,12GB。依舊報錯 OOM。

6.後面又將 mapreduce.input.fileinputformat.split.maxsize 從 1GB,減少為 512MB,256MB,從而增大 map 數量,縮小單個 map 處理文件的大小。依舊報錯 OOM。

7.最後啟用 hive.optimize.sort.dynamic.partition,增加 reduce 過程,作業執行成功。

8.最後查看結果文件大約 1.2TB,約為輸入文件的三分之壹。壹*** 1557 個分區,最大的分區文件為 2GB。

4.異常總結

對於這個異常,我們建議有以下三種方式來處理:

1.啟用 hive.optimize.sort.dynamic.partition,將其設置為 true。通過這個優化,這個只有 map 任務的 mapreduce 會引入 reduce 過程,這樣動態分區的那個字段比如日期在傳到 reducer 時會被排序。由於分區字段是排序的,因此每個 reducer 只需要保持壹個文件寫入器(file writer)隨時處於打開狀態,在收到來自特定分區的所有行後,關閉記錄寫入器(record writer),從而減小內存壓力。這種優化方式在寫 parquet 文件時使用的內存要相對少壹些,但代價是要對分區字段進行排序。

2.第二種方式就是增加每個 mapper 的內存分配,即增大 mapreduce.map.memory.mb 和 mapreduce.map.java.opts,這樣所有文件寫入器(filewriter)緩沖區對應的內存會更充沛。

3.將查詢分解為幾個較小的查詢,以減少每個查詢創建的分區數量。這樣可以讓每個 mapper 打開較少的文件寫入器(file writer)。

備註:

默認情況下,Hive 為每個打開的 Parquet 文件緩沖區(file buffer)分配 128MB。這個 buffer 大小由參數 parquet.block.size 控制。為獲得最佳性能,parquet 的 buffer size 需要與 HDFS 的 block size 保持對齊(比如相等),從而使每個 parquet 文件在單個 HDFS 的塊中,以便每個 I/O 請求都可以讀取整個數據文件,而無需通過網絡傳輸訪問後續的 block。

參考:

/blog/2014/03/how-to-use-parquet-with-impala-hive-pig-mapreduce/

/documentation/enterprise/latest/topics/cdh_ig_parquet.html

/qq_26937525/article/details/54946281

  • 上一篇:4月11日濟南市召開新冠肺炎疫情防控新聞發布會通報最新進展
  • 下一篇:如何把蘋果app導出 ipa
  • copyright 2024編程學習大全網