1、 控制hive任務中的map數: node
一般狀況下,做業會經過input的目錄產生一個或者多個map任務。
主要的決定因素有: input的文件總個數,input的文件大小,集羣設置的文件塊大小(目前爲128M, 可在hive中經過set dfs.block.size;命令查看到,該參數不能自定義修改);sql
舉例:
a) 假設input目錄下有1個文件a,大小爲780M,那麼hadoop會將該文件a分隔成7個塊(6個128m的塊和1個12m的塊),從而產生7個map數
b) 假設input目錄下有3個文件a,b,c,大小分別爲10m,20m,130m,那麼hadoop會分隔成4個塊(10m,20m,128m,2m),從而產生4個map數
即,若是文件大於塊大小(128m),那麼會拆分,若是小於塊大小,則把該文件當成一個塊。apache
是否是map數越多越好?
答案是否認的。若是一個任務有不少小文件(遠遠小於塊大小128m),則每一個小文件也會被當作一個塊,用一個map任務來完成,而一個map任務啓動和初始化的時間遠遠大於邏輯處理的時間,就會形成很大的資源浪費。並且,同時可執行的map數是受限的。ide
如何合併小文件,減小map數?
假設一個SQL任務:
Select count(1) from popt_tbaccountcopy_mes where pt = ‘2012-07-04’;
該任務的inputdir /group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04
共有194個文件,其中不少是遠遠小於128m的小文件,總大小9G,正常執行會用194個map任務。
Map總共消耗的計算資源: SLOTS_MILLIS_MAPS= 623,020oop
我經過如下方法來在map執行前合併小文件,減小map數: set mapred.max.split.size=100000000; set mapred.min.split.size.per.node=100000000; set mapred.min.split.size.per.rack=100000000; set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 再執行上面的語句,用了74個map任務,map消耗的計算資源:SLOTS_MILLIS_MAPS= 333,500 對於這個簡單SQL任務,執行時間上可能差很少,但節省了一半的計算資源。 大概解釋一下,100000000表示100M, set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;這個參數表示執行前進行小文件合併, 前面三個參數肯定合併文件塊的大小,大於文件塊大小128m的,按照128m來分隔,小於128m,大於100m的,按照100m來分隔,把那些小於100m的(包括小文件和分隔大文件剩下的), 進行合併,最終生成了74個塊。
如何適當的增長map數? 大數據
當input的文件都很大,任務邏輯複雜,map執行很是慢的時候,能夠考慮增長Map數,來使得每一個map處理的數據量減小,從而提升任務的執行效率。 假設有這樣一個任務: Select data_desc, count(1), count(distinct id), sum(case when …), sum(case when ...), sum(…) from a group by data_desc 若是表a只有一個文件,大小爲120M,但包含幾千萬的記錄,若是用1個map去完成這個任務,確定是比較耗時的,這種狀況下,咱們要考慮將這一個文件合理的拆分紅多個, 這樣就能夠用多個map任務去完成。 set mapred.reduce.tasks=10; create table a_1 as select * from a distribute by rand(123); 這樣會將a表的記錄,隨機的分散到包含10個文件的a_1表中,再用a_1代替上面sql中的a表,則會用10個map任務去完成。 每一個map任務處理大於12M(幾百萬記錄)的數據,效率確定會好不少。
看上去,貌似這兩種有些矛盾,一個是要合併小文件,一個是要把大文件拆成小文件,這點正是重點須要關注的地方,
根據實際狀況,控制map數量須要遵循兩個原則:使大數據量利用合適的map數;使單個map任務處理合適的數據量;.net
2、 控制hive任務的reduce數: code
Hive本身如何肯定reduce數:
reduce個數的設定極大影響任務執行效率,不指定reduce個數的狀況下,Hive會猜想肯定一個reduce個數,基於如下兩個設定:
hive.exec.reducers.bytes.per.reducer(每一個reduce任務處理的數據量,默認爲1000^3=1G)
hive.exec.reducers.max(每一個任務最大的reduce數,默認爲999)
計算reducer數的公式很簡單N=min(參數2,總輸入數據量/參數1)
即,若是reduce的輸入(map的輸出)總大小不超過1G,那麼只會有一個reduce任務;
如:select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt;
/group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04 總大小爲9G多,所以這句有10個reduceorm
調整reduce個數方法一:
調整hive.exec.reducers.bytes.per.reducer參數的值;
set hive.exec.reducers.bytes.per.reducer=500000000; (500M)
select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt; 此次有20個reduceblog
調整reduce個數方法二;
set mapred.reduce.tasks = 15;
select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt;此次有15個reduce
reduce個數並非越多越好;
同map同樣,啓動和初始化reduce也會消耗時間和資源;
另外,有多少個reduce,就會有多少個輸出文件,若是生成了不少個小文件,那麼若是這些小文件做爲下一個任務的輸入,則也會出現小文件過多的問題;
一樣的,在設置reduce個數的時候也須要考慮這兩個原則:使大數據量利用合適的reduce數;使單個reduce任務處理合適的數據量;
轉自:https://blog.csdn.net/longzilong216/article/details/20711433