1. 程式人生 > >hive map reduce 引數設定

hive map reduce 引數設定

現象:

1.目前每日load出來的問題sql,最終的結果檔案裡面很多都只有一條資料。

2.資源影響巨大,對照指令碼統計出來的sql執行時間,手動執行sql的時間是其十分之一到三分之一。

3.不少sql執行時的map數量能達到1000-3000,但是reduce數量在1左右。

由於每天load出的excle文件,sjzx租戶的sql過長,手動無法執行,其它租戶的sql抽取時又存在亂碼問題,僅針對了sjzx_b租戶的sql進行了分析,但是問題和優化可通用。

首先mapreducemap數量是無法直接控制的,所以只能通過對map數量的影響因素方面進行調整,從而間接影響hive sql執行時map的數量。

目前我們叢集的情況:

(set) mapred.max.split.size=256000000   -------決定每個map處理的最大檔案大小,B

(set) mapred.min.split.size.per.node=1    -------節點處理的最小檔案大小

(set) mapred.min.split.size.per.rack=1     ------機架中可以處理的最小檔案大小

(set) mapred.reduce.tasks=-1            ------設定reduce數量,這裡-1也就是自動計算出需要reduce的個數

(set) hive.exec.reducers.bytes.per.reducer=256000000

   ---------每個reduce處理的資料量

(set) hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat

                               ---------map端做combiner操作

(set) hive.merge.mapredfiles=true        ---------小檔案合併

(set) hive.exec.reducers.bytes.per.reducer=256000000------控制一個job當中會有多少個reduce來處理,依據的是輸入檔案的總大小

(set) hive.exec.reducers.max=1009    ----------控制最大reduce數量

調整影響:

設定map,可能帶來叢集之間的io,因為可能涉及到檔案的合併;設定reduce,則會對最後的結果檔案個數造成直接影響;reduce太少,會導致reduce端的資料量太大,影響執行效率,導致整個job都不能結束;reduce太小,則會產生大量的結果檔案,合併代價大,佔用namenode的記憶體空間。

邏輯:

根據mapred.max.split.size來確認需要啟動多少個map數。

比如檔案大小260M280M,則會啟動兩個map,剩餘的4M24M先做保留。

再根據mapred.min.split.size.per.node來針對剩下的檔案做操作,如果設定為1,則表示剩餘的檔案自己啟動一個map,這裡會啟動2兩個;如果設定為28*1024*1024,則檔案會合併成一個,啟動一個map。但是正常情況下,不可能正好設定成28*1024*1024,也就是說,還是會產生剩餘的檔案。

最後根據mapred.min.split.size.per.rack,來決定是否要進行合併,對再次剩餘的檔案獨自產生一個map

因此針對控制map數量和reduce數量:

針對map數量:

set mapred.max.split.size=

set mapred.min.split.size.per.node=

set mapred.min.split.size.per.rack=

針對reduce數量:

set mapred.reduce.tasks=

set hive.exec.reducers.bytes.per.reducer=

優化手段:

1.針對那些map數量達到1000-3000sql,可以通過設定mapred.max.split.size臨時引數來減少map數量,目前測試的結果顯示1000-2000map數量的sql,設定在512M2000-3000map數量的設定在1G,執行時間有明顯減少

2.count(distinct xxx)語句的改寫

比如:

insert into table lzl2 partition(date_dt = '2018-02-03') select 'FIN_PG_BAL_ITEM_71' ,count(distinct bal_item_id) from FIN_PG_BAL_ITEM_71

這個sql執行時間是57分鐘,map數量367reduce數量1

時間如此之長的分析:

Mapreduce過程中,理論上map階段會進行combine操作對輸出結果做合併消重,以減少reduce階段的資料量。但是如果使用了distinct,就會發生map階段無法進行combine操作,對統計大量資料時,會導致最終map的全部輸出由單個reduce task來處理,也就是說這個唯一的reduce task需要shuffle大量的資料,並且要進行排序聚合等處理,會導致map過程可能十幾秒就完成,但是reduce過程需要長達30-50分鐘。

直接增加reduce數量,set mapred.reduce.tasks=10;但是在執行過程中,發現reduce數量不管怎麼改,實際執行時都是1

這是因為hive在處理count這種全聚合操作時,會忽略掉使用者指定的reduce task數量,而強制使用1,這樣會造成單一的reduce task瓶頸。

改寫成:

insert into table lzl2 partition(date_dt = '2018-02-03') select 'FIN_PG_BAL_ITEM_71' ,t.b from (select count(*) as b from (select distinct bal_item_id from pdm.FIN_PG_BAL_ITEM_71) a) t;

第一階段:map數量358reduce數量485

第二階段:map數量179reduce數量1

總執行時長117秒。

分析:

這樣改寫的sql在執行時,會被分成兩個job

第一階段job是選出全部的非重複bal_item_id,雖然在這階段由於distinct對map階段的combine產生了抑制,但是可以通過調整reduce的數量來提高這階段shuffle效率,這裡我進行了兩種對比,set mapred.reduce.tasks=-1set mapred.reduce.tasks=

10,前者表示讓mr自己去計算需要啟動多少個reduce,後者認為設定,由於無法相對準備的給出reduce的數量,所以後者的效率還是不算高,因此選擇了預設配置set mapred.reduce.tasks=-1

PS:預設設定很省事,但是絕不是最佳,前期優化可以這樣選擇。

第二階段job,進行count(*),雖然這階段強制指定了reduce task,但是由於第一階段的job已經對資料進行合併去重的操作,這階段的map只需輸出一個合併後的計數即可,因此較少的map輸出不會成為單一reduce task的瓶頸。