1. 程式人生 > >hive中控制map和reduce數量的簡單實現方法

hive中控制map和reduce數量的簡單實現方法

0、先說結論:

  由於mapreduce中沒有辦法直接控制map數量,所以只能曲線救國,通過設定每個map中處理的資料量進行設定;reduce是可以直接設定的。 
控制map和reduce的引數

set mapred.max.split.size=256000000;        -- 決定每個map處理的最大的檔案大小,單位為B
set mapred.min.split.size.per.node=1;         -- 節點中可以處理的最小的檔案大小
set mapred.min.split.size.per.rack=1;         -- 機架中可以處理的最小的檔案大小
方法1
set
mapred.reduce.tasks=10; -- 設定reduce的數量 方法2 set hive.exec.reducers.bytes.per.reducer=1073741824 -- 每個reduce處理的資料量,預設1GB
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

補充說明:一個叢集可以有多個機架,一個機架有1至多個節點,這裡的叢集是mapreduce不是yarn,yarn沒有詳細瞭解過,另外如果想要實現map中的資料合併需要設定下面的引數,叢集預設就是這個格式

set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
;
  • 1

需要確認的問題: 
 a.我們該設定多少個map多少個reduce才合適? 
  map數普遍是通過執行時長來確認的,至少應當保證每個map執行時長在1分鐘以上,太短的話意味著大量重複的jvm啟用和銷燬。具體設定要根據具體任務來處理,有些任務佔用cpu大,有些佔用io大。 
  我這邊的話因為大任務經常搞了上千個map,作為小叢集影響還是蠻大的,所以只對監控到的hql產生過大的map和reduce進行調整,經過一些簡單測試,map數保證在三四百個其實不影響執行效率。

 b.設定了上面的引數會帶來什麼影響? 
  設定map的話,影響不是很大,可能會帶來更多的叢集之間的io,畢竟要做節點之間的檔案合併 
  設定reduce的話,如果使用mapred.reduce.tasks,這個影響就大了,至少會造成同一個session每一個mr的job的reduce都是這麼多個,而且reduce個數意味著最後的檔案數量的輸出,如果小檔案太多的話可以開啟reduce端的小檔案合併引數,set hive.merge.mapredfiles=true

1、控制map數量的三個引數的邏輯概念

  可以簡單的理解為叢集對一個表分割槽下面的檔案進行分發到各個節點,之後根據mapred.max.split.size確認要啟動多少個map數,邏輯如下 
  a.假設有兩個檔案大小分別為(256M,280M)被分配到節點A,那麼會啟動兩個map,剩餘的檔案大小為10MB和35MB因為每個大小都不足241MB會先做保留 
  b.根據引數set mapred.min.split.size.per.node看剩餘的大小情況並進行合併,如果值為1,表示a中每個剩餘檔案都會自己起一個map,這裡會起兩個,如果設定為大於45*1024*1024則會合併成一個塊,併產生一個map 
  如果mapred.min.split.size.per.node為10*1024*1024,那麼在這個節點上一共會有4個map,處理的大小為(245MB,245MB,10MB,10MB,10MB,10MB),餘下9MB 
  如果mapred.min.split.size.per.node為45*1024*1024,那麼會有三個map,處理的大小為(245MB,245MB,45MB) 
  實際中mapred.min.split.size.per.node無法準確地設定成45*1024*1024,會有剩餘並保留帶下一步進行判斷處理 
  c. 對b中餘出來的檔案與其它節點餘出來的檔案根據mapred.min.split.size.per.rack大小進行判斷是否合併,對再次餘出來的檔案獨自產生一個map處理

2、控制map數量的簡單實用方式

  我們執行一個hive語句,發現起了1000個map,這種情況對於當前的資料量來說是完全不必要的,同時還會影響其它使用者提交任務 
  這個時候希望map減小到250個左右,很簡單 
  將map處理的最大的檔案大小增大,256000000*4=1024000000 
引數修改為如下

set mapred.max.split.size=1024000000;
set mapred.min.split.size.per.node=1024000000;
set mapred.min.split.size.per.rack=1024000000;
  • 1
  • 2
  • 3

示例及測試如下

這裡寫圖片描述 
  修改引數之後,如下圖,可以看到map數量減少到370,至於為什麼單個map處理的資料量增大了,map數卻不是按倍數減少到1185/4=296個,原因在檔案合併過程中對於如何起map數並不是單純的看總的檔案大小,存在一些更優化的演算法,如考慮頻寬、IO、當前map分配等 
這裡寫圖片描述

3、控制reduce引數

  修改reduce的個數就簡單很多,直接根據可能的情況作個簡單的判斷確認需要的reduce數量,如果無法判斷,根據當前map數減小10倍,保持在1~100個reduce即可(注意,這個不同的叢集需求不同哈) 
設定引數如下 
set mapred.reduce.tasks=10 
不建議隨意設定reduce引數哈,可能調整引數更好一點 
set hive.exec.reducers.bytes.per.reducer=1073741824

4、控制map和rduce數的說明

  1、因為set引數的設定是session級別的,Toad for Cloud(青蛙)第三方軟體中暫時沒有發現如何使set的引數設定有效的,所以請使用CRT等工具連線到linux的介面中進行使用,使用hive命令連線hive叢集,一次設定只要不結束這次連線,那麼引數是始終有效的。 
  2、注意各引數的設定大小,不要衝突,否則會異常,大小順序如下 
mapred.max.split.size <= mapred.min.split.size.per.node <= mapred.min.split.size.per.rack 
  3、這種減少map數的行為是否能帶來更短的執行時間,需要具體分析,map數也不是越少越好,減少了map數,單個map處理的資料量就上升,需要更多的時間,同時也因為需要合併節點內、節點間甚至機架之間的資料需要更多的IO和頻寬。 
  引數的設定本質是根據檔案情況、系統情況、資料計算情況進行的一個平衡考慮,有取有舍,我們需要遵循的規則就是:使大資料量利用合適的map數;使單個map任務處理合適的資料量 
  4、reduce數同3