Hadoop是怎麼分塊Block的?

 

 

 

  很少說,直接上乾貨!html

 

hadoop的分塊有兩部分。
 node

  第一部分就是數據的劃分(即把File劃分紅Block),這個是物理上真真實實的進行了劃分,數據文件上傳到HDFS裏的時候,須要劃分紅一塊一塊,每塊的大小由hadoop-default.xml裏配置選項進行劃分。網絡

<property>  
  <name>dfs.block.size</name>  
  <value>67108864</value>  
  <description>The default block size for new files.</description>  
</property>  

  這個就是默認的每一個塊64MB。數據劃分的時候有冗餘,個數是由如下配置指定的。oop

<property>  
  <name>dfs.replication</name>  
  <value>3</value>  
  <description>Default block replication.   
  The actual number of replications can be specified when the file is created.  
  The default is used if replication is not specified in create time.  
  </description>  
</property>    

  具體的物理劃分步驟由Namenode決定。spa

 

 

 

  第二種劃分是由InputFormat這個接口來定義的,其中有個getSplits方法。這裏有一個新的概念:fileSplit。每一個map處理一個fileSplit,因此有多少個fileSplit就有多少個map(map數並非單純的由用戶設置決定的)。code

  咱們來看一下hadoop分配splits的源碼:orm

if ((length != 0) && isSplitable(fs, path)) {  
    long blockSize = file.getBlockSize();  
    long splitSize = computeSplitSize(goalSize, minSize, blockSize);  
    long bytesRemaining = length;  
      
    while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {  
        int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);  
        splits.add(new FileSplit(path, length-bytesRemaining, splitSize, blkLocations[blkIndex].getHosts()));  
        bytesRemaining -= splitSize;          
    }  
      
    if (bytesRemaining != 0) {  
      
    splits.add(new FileSplit(path, length-bytesRemaining, bytesRemaining,  blkLocations[blkLocations.length-1].getHosts()));        }  
  
} else if(length!=0) {  
  
    splits.add(new FileSplit(path,0,length,blkLocations[0].getHosts()));  
  
}else{  
  
    // Create empty hosts array for zero length files  
      
    splits.add(new FileSplit(path,0,length,new String[0]));  
}  

  從代碼能夠看出,一個塊爲一個splits,即一個map,只要搞清楚一個塊的大小,就能計算出運行時的map數。而一個split的大小是由goalSize, minSize, blockSize這三個值決定的。computeSplitSize的邏輯是,先從goalSize和blockSize兩個值中選出最小的那個(好比通常不設置map數,這時blockSize爲當前文件的塊size,而goalSize是文件大小除以用戶設置的map數獲得的,若是沒設置的話,默認是1),在默認的大多數狀況下,blockSize比較小。而後再取bloceSize和minSize中最大的那個。而minSize若是不經過」mapred.min.split.size」設置的話(」mapred.min.split.size」默認爲0),minSize爲1,這樣得出的一個splits的size就是blockSize,即一個塊一個map,有多少塊就有多少map。xml

  上面說的是splitable的狀況,unsplitable能夠根據實際狀況來計算,通常爲一個文件一個map。htm

  下面是摘自網上的一個總結:blog

  幾個簡單的結論:
    一、一個split不會包含零點幾或者幾點幾個Block,必定是包含大於等於1個整數個Block。
    二、 一個split不會包含兩個File的Block,不會跨越File邊界。
    三、split和Block的關係是一對多的關係。
    四、maptasks的個數最終決定於splits的長度。

  還有一點須要說明,在FileSplit類中,有一項是private String[] hosts;
  看上去是說明這個FileSplit是放在哪些機器上的,實際上hosts裏只是存儲了一個Block的冗餘機器列表。
  好比有個fileSplit 有4個block: Block11, Block12, Block13,Block14,這個FileSplit中的hosts裏最終存儲的是Block11自己和其備份所在的機器列表,也就是說 Block12,Block13,Block14存在哪些機器上沒有在FileSplit中記錄。

  FileSplit中的這個屬性有利於調度做業時候的數據本地性問題。若是一個tasktracker前來索取task,jobtracker就會找個 task給他,找到一個maptask,得先看這個task的輸入的FileSplit裏hosts是否包含tasktracker所在機器,也就是判斷 和該tasktracker同時存在一個機器上的datanode是否擁有FileSplit中某個Block的備份。

  但總之,只能牽就一個Block,其餘Block就要從網絡上傳。不過對於默認大多數狀況下的一個block對應一個map,能夠經過修改hosts使map的本地化數更多一些。 在講block的hosts傳給fileSplit時,hosts中的主機地址能夠有多個,表示map能夠從優先從這些hosts中選取(只是優先,但hdfs還極可能根據當時的網絡負載選擇不是hosts中的主機起map task)。

  知道這個特性以後,能夠修改傳回給fileSplit的hosts,在列表中只寫block所在的那些hosts,這樣hdfs就會優先將這些map放到這些hosts上去執行,因爲hosts上有該block,就省掉了網絡傳輸數據的時間。

  這樣作的話,在job不少的時候,可能會出現hot spot,即數據用的越多,它所在hosts上的map task就會越多。因此在考慮修改傳給fileSplit的時候要考慮平衡諸多因素。

相關文章
相關標籤/搜索