確定map任務數時依次優先參考如下幾個原則:
1) 每個map任務使用的內存不超過800M,盡量在500M以下
比如處理256MB數據需要的時間為10分鍾,內存為800MB,此時如果處理128MB時,內存可以減小為400MB,則選擇每一個map的處理數據量為128MB
2) 每個map任務運行時間控制在大約20分鍾,最好1-3分鍾
比如處理256MB數據需要的時間為30分鍾,內存為200MB,則應該考慮減小map的計算時間,比如將每一個map的處理數據量設置為128MB,將時間減小為15分鍾。
3) 每個map任務處理的最大數據量為一個HDFS塊大小(目前為256MB),一個map任務處理的輸入不能跨文件
比如指定map任務數為N,輸入數據總量為S。如果S / N > 256MB,平台會自動增加map任務數使每個map任務處理數據量不超過256MB;如果S / N < 256MB,平台認為每個map任務最多處理S/N大小的數據,但是一個map任務的輸入不能跨文件,所以可能有的文件切分到最后一部分時較小於S/N,那么下一個map任務的輸入小於平均,最終的map任務數大於N。最終實際運行的map任務數可以在JobTracker監控頁面查看。
4) map任務總數不超過平台可用的任務槽位
如果在一個map處理256MB時就能將平台可用的任務槽位占滿,此時不應該再增加map任務數。
~ 《Hadoop-v2_Streaming 使用手冊》
可以通過 -D mapred.map.tasks=mapper個數 來調整
(也可以通過mapred.max.split.size(ex. =512000000)調節邏輯塊的大小。但是對於hadoop streaming: split size大小是被自動優化過的默認值,只調split.size參數可能不能生效,可以配合調inputformat等)
block size和split size的區別
block size是hdfs中每個數據塊的物理大小,比如64MB, 128MB
一般來說,mapper在split時默認按照block size來分的,那么mapper的個數就是 data_size / block_size 向上取整。
split size是可以人為指定的邏輯塊的大小,當希望mapper數量小一些的時候,可以把split size指定的大一些,這樣 data_size / split_size 向上取整之后就是新的mapper個數。
為什么要調整mapper的個數
每個mapper相當於可以執行並行計算的工人,mapper多一些,就多一些數據被並行計算,這樣看起來似乎mapper多一些運行的更快;
但是要考慮到由於集群資源限制,有時候並不是設置的所有mapper都可以並行執行,是先執行一些mapper,完成一個mapper再調度新的mapper,這樣就有任務調度時候的時間開銷。
(1) 如果每個mapper分到的數據比較小,那么這個mapper執行是比較快的,比如幾十秒,那么hadoop就要去調度執行其他的mapper,這里有個調度任務的時間。
如果mapper數量非常大,而每個mapper執行時間又很短,那么可能很大一部分時間不是用於執行任務了,而是用於調度了,這樣總的運行時間就會較長,不夠高效。
看上面的tip提到的每個mapper運行時間的建議,一般可以通過調節split size的大小,即控制給每個mapper的數據大小,來調節每個mapper的運行時間,進而提高運行效率。
(2) 如果每個mapper分到的數據比較大,一方面是內存占用比較大,容易爆內存;另一方面,如果單個mapper運行時間過長,這個mapper壓力是比較大的,如果可以多設置一些mapper,可以更好的實現並行運算,進而提高效率。