MapReduce -- task 的執行

下面來看下,MapReduce用戶對task執行的更多控制

The Task Execution Environment

Hadoop爲map task和reduce task提供了運行環境信息。例如,一個map task 可以知道它正在處理的文件的名稱,和一個map或reduce task可以找出已經嘗試的次數、下表中的屬性都可以在job的配置信息中訪問到,在老的MapReduce API中可以通過Mapper或reducer的configuer()方法獲得這些信息,其中配置作爲參數傳入。在新的API中,這些屬性可以通過context對象獲得,該對象被傳入到Mapper和Reducer的方法中。


Speculative Execution(推測執行)

MapReduce 模型將job分割成若干task,然後並行運行的這些task的,這使得job的整體執行時間要少於順序執行這些task的時間。那麼執行緩慢的task,將影響job的執行時間,當一個job有上百或上千個task時,有幾個“拖後腿”task是很常見的。

Task緩慢有多種原因,包括硬件故障、軟件配置錯誤,但是緩慢的原因又很難檢測出來,因爲job已成功完成,儘管完成時間比預期的要長。Hadoop不會試着去分析和修復運行緩慢的task,而是自動推測,試着啓動另外一個等效的task。這就是所謂的task“推測執行”。

speculative execution並不是在大約同一時間同時運行兩個task,而是,調度器跟蹤所有task的進度,推測執行只對明顯低於平均速率的task(一般佔較小比例),才啓動一個副本task,當一個task成功完成,那麼其所有正在運行的副本task將被殺死,因爲不在需要了。如果原task在speculative task之前完成,那麼speculative task將被殺死;如果speculative task 先完成,那麼原task將被殺死。

Speculative Execution僅是一個優化措施,並不能使job的運行更可靠。如果存在bug,可能會引起task的掛起或運行緩慢。

Speculative Execution默認是啓用的,也可以單獨的爲map或reduce task、job、集羣範圍啓用或停用。相關屬性見下表:


Speculative Execution的目的就是減少job的執行時間的,但這是以犧牲集羣效率爲代價的。對於一個比較繁忙的集羣,speculative execution 會降低整體的吞吐量,因爲冗餘的task正在執行。處於這個原因,一些集羣管理員通常會關閉speculative execution,但用戶可以爲個別的job開啓speculative  execution。Hadoop老版本更是如此,因爲它在調度speculative task時會過度使用speculative execution。

一個關閉speculative execution例子就是reduce task,因爲任何speculative task會使用和原reduce task同樣的map 輸出,這就明顯增加了集羣的網絡傳輸。

Output Committers

MapReduce使用一個commit協議,來確保job和task的要麼完全成功,要麼完全失敗。該行爲是由OutputCommitter實現,在舊的MapReduce API中,是通過掉JobConf的setOutputCommitter()方法或通過setting mapred.output.committer.class屬性來設置。在新的MapReduce API中,OutputCommiter是由OutputFormat的getOutputCommitter()方法確定的,默認爲FileOutputCommitter,這是基於文件處理的MapReduce。另外,如果有特殊需求,也可以爲job或task自定義一個OutputCommitter或寫一個新的實現。

OutputCommitter的API如下:

public abstract class OutputCommitter {
  public abstract void setupJob(JobContext jobContext) throws IOException;
  public void commitJob(JobContext jobContext) throws IOException { }
  public void abortJob(JobContext jobContext, JobStatus.State state) throws IOException { }
  public abstract void setupTask(TaskAttemptContext taskContext) throws IOException;
  public abstract boolean needsTaskCommit(TaskAttemptContext taskContext) throws IOException;
  public abstract void commitTask(TaskAttemptContext taskContext) throws IOException;
  public abstract void abortTask(TaskAttemptContext taskContext) throws IOException;
}
setupJob()方法在job運行之前調用,主要做一些初始化操作。對於FileOutputCommitter,該方法會爲map輸出創建最終的輸出目錄${mapreduce.output.fileoutputformat.outputdir},和臨時工作空間_temporary作爲其下的子目錄。

如果job成功,就會調用commitJob()方法,它將會刪除臨時工作空間,並創建一個隱藏的空的標記文件_SUCCESS,表示job成功完成。如果job沒有成功,將會調用abortJob()方法,它帶有一個state對象表示job是失敗或被殺死(例如用戶),默認它也會刪除臨時工作空間。

setupTask()方法是針對對Task的,它在task運行前調用,默認不做任何事情,因爲在寫task輸出時已經爲task的輸出創建了臨時目錄。

task的commit階段是可選,也可以通過needsTaskCommit().方法返回false來禁用,這將會使框架不必運行分佈式提交協議,並且也不會調用commitTask() 、 abortTask()方法。當task沒有輸出可寫時,FileOutputCommitter將跳過commit階段。

如果task成功,將會調用commitTask()方法,它會將臨時輸出目錄(爲避免衝突,不同的task嘗試以嘗試ID作爲目錄名)移動到最終的輸出路徑${mapreduce.output.fileoutputformat.outputdir}。否則,將調用abortTask()方法,它將刪除臨時輸出目錄。

MapReduce框架對於一個特定的task,如果多個任務嘗試的實例,可以確保僅有一個可以提交,其它的將被放棄。出現這種情況是因爲某些原因第一次嘗試失敗,它將被放棄,之後的嘗試成功的將被提交。也可能會發生兩個嘗試task同時在運行,這種情況,先執行完成的先提交,另一個將被放棄。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章