天天看點

軟體開發——hive腳本使用tez引擎導緻記憶體溢出問題

作者:無八個

腳本使用tez引擎導緻記憶體溢出問題

問題描述

建立RCFlile儲存格式的表,當使用tez引擎向表中插入資料時,報記憶體溢出問題。

軟體開發——hive腳本使用tez引擎導緻記憶體溢出問題

問題處理

方案1:

将RCFile儲存格式的表改為ORCFile的存儲格式。

方案2:

在腳本的beeline指令後,添加參數

Yarn.app.mapreduce.am.resource.mb=XXX

Yarn.app.mapreduce.am.command-opts=XXXm

設定規則為Yarn.app.mapreduce.am.command-opts= Yarn.app.mapreduce.am.resource.mb*0.8

說明

RCFile和ORCFile的差別

RCFile

RCFile檔案格式是FaceBook開源的一種Hive的檔案存儲格式,首先将表分為幾個行組,對每個行組内的資料進行按列存儲,每一列的資料都是分開存儲,正是先水準劃分,再垂直劃分的理念。

軟體開發——hive腳本使用tez引擎導緻記憶體溢出問題

在存儲結構上:

如上圖是HDFS内RCFile的存儲結構,我們可以看到,首先對表進行行劃分,分成多個行組。一個行組主要包括:16位元組的HDFS同步塊資訊,主要是為了區分一個HDFS塊上的相鄰行組;中繼資料的頭部資訊主要包括該行組内的存儲的行數、列的字段資訊等等;資料部分我們可以看出RCFile将每一行,存儲為一列,将一列存儲為一行,因為當表很大,我們的字段很多的時候,我們往往隻需要取出固定的一列就可以。

在一般的行存儲中 select a from table,雖然隻是取出一個字段的值,但是還是會周遊整個表,是以效果和select * from table 一樣,在RCFile中,像前面說的情況,隻會讀取該行組的一行。

在一般的列存儲中,會将不同的列分開存儲,這樣在查詢的時候會跳過某些列,但是有時候存在一個表的有些列不在同一個HDFS塊上(如下圖),是以在查詢的時候,hive重組列的過程會浪費很多IO開銷。

軟體開發——hive腳本使用tez引擎導緻記憶體溢出問題

而RCFile由于相同的列都是在一個HDFS塊上,是以相對列存儲而言會節省很多資源。

在存儲空間上:

RCFile采用遊程編碼,相同的資料不會重複存儲,很大程度上節約了存儲空間,尤其是字段中包含大量重複資料的時候。

懶加載:

資料存儲到表中都是壓縮的資料,Hive讀取資料的時候會對其進行解壓縮,但是會針對特定的查詢跳過不需要的列,這樣也就省去了無用的列解壓縮。

針對行組來說,會對一個行組的a列進行解壓縮,如果目前列中有a>1的值,然後才去解壓縮c。若目前行組中不存在a>1的列,那就不用解壓縮c,進而跳過整個行組。

ORCFile

ORC是在一定程度上擴充了RCFile,是對RCFile的優化。

軟體開發——hive腳本使用tez引擎導緻記憶體溢出問題

存儲結構上

根據結構圖,我們可以看到ORCFile在RCFile基礎上引申出來Stripe和Footer等。每個ORC檔案首先會被橫向切分成多個Stripe,而每個Stripe内部以列存儲,所有的列存儲在一個檔案中,而且每個stripe預設的大小是250MB,相對于RCFile預設的行組大小是4MB,是以比RCFile更高效。

Postscripts中存儲該表的行數,壓縮參數,壓縮大小,列等資訊

Stripe Footer中包含該stripe的統計結果,包括Max,Min,count等資訊

FileFooter中包含該表的統計結果,以及各個Stripe的位置資訊

IndexData中儲存了該stripe上資料的位置資訊,總行數等資訊

RowData以stream的形式儲存了資料的具體資訊

Hive讀取資料的時候,根據FileFooter讀出Stripe的資訊,根據IndexData讀出資料的偏移量進而讀取出資料。

網友有一幅圖,形象的說明了這個問題:

軟體開發——hive腳本使用tez引擎導緻記憶體溢出問題

存儲空間上

ORCFile擴充了RCFile的壓縮,除了Run-length(遊程編碼),引入了字典編碼和Bit編碼。

采用字典編碼,最後存儲的資料便是

字典中的值,每個字典值得長度以及字段在字典中的位置

至于Bit編碼,對所有字段都可采用Bit編碼來判斷該列是否為null,

如果為null則Bit值存為0,否則存為1,對于為null的字段在實際編碼的時候不需要存儲,也就是說字段若為null,是不占用存儲空間的。

總結ORCFile儲存格式相比RCFile格式的優點為:

當ORC writer寫資料時,會将整個stripe(資料存儲單元)儲存在記憶體中。由于stripe的預設值一般比較大,當有多個ORC writer同時寫資料時,可能導緻記憶體不足。為了降低這種并發寫時的記憶體消耗,ORC檔案中引入了一個記憶體管理器。在一個Map或者Reduce任務中記憶體管理器會設定一個門檻值,這個門檻值會限制write使用的總記憶體大小。當有新的writer需要寫出 資料時,會向記憶體管理器注冊其大小(一般也就是stripe的大小),當記憶體管理器接收到的總注冊大小超過門檻值時,記憶體管理器會将stripe的實際大小按該writer注冊的記憶體大小與總注冊記憶體大小的比例進行縮小。當有writer關閉時,記憶體管理器會将其注冊的記憶體從總注冊的記憶體中登出。

修改參數配置

  1. 為什麼修改會話級

當該值作為全局參數時,每啟動一個beeline都會作為預設參數,可能造成記憶體浪費

  1. 為什麼調大這兩個參數

Tez am需要的記憶體比較多,當map和 reduce 的task個數多的時候尤其要調大,修改為orc資料存在壓縮,task數量會減少,所需記憶體也會減少

  1. 什麼是am

Am即ApplicationMaster

Yarn上的任務,會先驅動一個am用來申請運作任務的資源,管理運作的任務。

當申請的資源較小時,不滿足任務的實際運作情況,則會報錯。

當申請的資源較大時,則會造成資源的浪費。

繼續閱讀