如何合并小檔案,減少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,020
我通過以下方法來在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任務處理合适的資料量;
本文轉自 yntmdr 51CTO部落格,原文連結:http://blog.51cto.com/yntmdr/1740587,如需轉載請自行聯系原作者