1. 背景
Speculative Task,又叫推測式任務,是指在分佈式集羣環境下,因爲程序bug,負載不均衡或者資源分佈不均,造成同一個job的多個task運行速度不一致,有的task運行速度明顯慢於其他task(比如:一個job的某個task進度只有10%,而其他所有task已經運行完畢),則這些task拖慢了作業的整體執行進度,爲了避免這種情況發生,Hadoop會爲該task啓動speculative task,讓該speculative task與原始task同時運行,哪個先運行完,則使用它的結果。
Speculative Task思路是以空間換時間的,同時啓動多個相同task,哪個完成的早,則採用哪個task的結果,這樣明顯可以提高任務計算速度,但是,這樣卻會佔用更多的資源,在集羣資源緊缺的情況下,合理的控制Speculative Task,可在多用少量資源情況下,減少大作業的計算時間。
本文主要介紹了Hadoop各個版本中Speculative Task設計思路,並指出了各自的不足及改進之處。
2. Hadoop 0.20.2和1.0.0中的算法
【算法流程】
如果一個task滿足以下條件,則會爲該task啓動speculative task:
(1)該task還未啓動任何speculative task(TaskInProgress僅對應一個running的task)
(2)在60s內落後(同一個作業所有task的)平均進度20%
某個Task可能對應多個正在運行的attempt task,任何一個運行結束,則會kill(不是fail)其他task。
【相關代碼】
1
2
3
4
5
6
7
8
9
10
11
12
|
boolean hasSpeculativeTask( long currentTime,
double averageProgress)
{ //
these constants should be examined //
in more depth eventually... // if (!skipping
&& activeTasks.size() <= MAX_TASK_EXECS && (averageProgress
- progress >= SPECULATIVE_GAP) && (currentTime
- startTime >= SPECULATIVE_LAG) &&
completes == 0 &&
!isOnlyCommitPending()) { return true ; } return false ; } |
【存在問題】
以上算法可能造成以下幾個問題:
(1) 作業的某個task被卡在87.7%處(MAPREDUCE-94)
(2) 當作業將要運行結束時,總不會啓動speculative task
(3) 各個參數不可配置(SPECULATIVE_GAP,SPECULATIVE_LAG),不夠靈活。
3. Hadoop 0.21.0中的算法
爲了對Hadoop-0.20.2中的算法進行改進,Hadoop-0.21.0進行了以下優化:
(1) 添加了三個可配置選項
mapreduce.job.speculative.slownodethreshold,默認是1,用於判斷某個TaskTracker是否適合啓動某個task的speculative task
mapreduce.job.speculative.slowtaskthreshold,默認是1,用於判斷某個task是否可以啓動speculative task
mapreduce.job.speculative.speculativecap, 默認是0.1,用於限定某個job最多同時啓動的spculative task的數目
(2) 限定條件
如果一個tasktracker/job/task滿足以下條件,則會在該tasktracker上爲該task啓動一個speculative task:
(1) Job已經啓動的specutive task數目小於SpeculativeCap
(2) 該TaskTracker上該Job的所有task平均進度不小於SlowNodeThreshold,具體判斷方法爲:
tasktracker. mean-job.progessRate >job.std*job. SlowNodeThreshold
其中,tasktracker. Mean爲該job在該tasktracker正在運行/已經運行完成的task的平均進度,job.progessRate爲該作業的平均計算速度,job.std爲該作業所有task計算速度的標準方差。
(3) 按照Task剩餘時間,對Task進行排序
Task剩餘時間定義爲:(1-progress) / progressRate,其中process爲task當前進度,progressRate爲task的平均計算速度:progressRate= progress/deltaTime,其中deltaTime爲該task啓動以來所經歷的時間
(4) 選擇一個剩餘時間最多,且 mean-progessRate >std*SlowTaskThreshold的task,併爲該task啓動speculative task,,其中mean爲所有task平均計算速度,std爲所有task計算速度的標準方差。
(3) 存在問題
當一個作業只有一個task時,所有task的計算速度的標準方差爲0,因而,總會爲這樣的作業啓動speculative task
如果一個作業僅有一個task正在運行,則所有task的標準方差仍未0,Hadoop很可能爲其他所有task啓動speculative task。
在Hadoop中,reduce task進度(對應上面的progress變量)計算很不合理,採用的方法是,將reduce task分爲三個子過程:shuffle(copy),sort和reduce,各個階段佔進度的1/3,比如,一個task的shuffle階段剛結束,它的進度應該是33.3%。 對於大部分作業,reduce task的進度變化並不是均勻的,一個task在某一時刻進度爲33.3%,下一秒進度可能變爲66.6%,這主要是因爲sort階段所做工作非常少,時間很短。也正是由於以上原因,reduce task很容易被誤判速度過慢,進而啓動speculative task。一種可行的解決方案是將sort階段利用某個數學模型平滑處理。
4. 終極解決方案
拖後腿task出現的原因是系統負載不均衡和資源分配不均。尤其是在異構Hadoop集羣中,拖後腿task會經常出現,而且最好不要打開speculative task功能,否則會出現大量的speculative task,造成嚴重的資源浪費,因爲當前所有的speculative task解決方案均是假設集羣是同構的。
爲什麼會造成這種問題?根本原因這種基於speculative task來解決拖後腿task是有問題的。拖後腿task最終應該通過調度器解決:每個TaskTracker通過heartbeat彙報自己機器上的資源分佈情況和當前資源使用情況,比如CPU個數,CPU利用率,內存剩餘量,IO負載等,然後由調度器根據當前資源使用情況,動態對任務進行調度(參考https://issues.apache.org/jira/browse/MAPREDUCE-1380),進而最大限度避免產生拖後腿task。
關於拖後腿task,還有一個需要解決的問題是,防止爲某個task啓動speculative task後,該task又變成拖後腿task,比如:某個node上所有task均往一個磁盤上寫數據,且該磁盤負載很重,而此時又將一個speculative task調度到該節點上(也往該磁盤上寫數據),此時,該speculative task變得緩慢,因而有人提出了Hadoop disk scheduler,具體參考:https://issues.apache.org/jira/browse/MAPREDUCE-2636
5. 關於Speculative Task的Hadoop代碼
Hadoop中,關於推測式任務的相關代碼均在文件JobInProgress.java和TaskInProgress.java中,JobInProgress.java主要函數定義如下:
1
2
3
|
protected synchronized
TaskInProgress findSpeculativeTask( Collection<TaskInProgress>
list, String taskTrackerName, String
taskTrackerHost, TaskType taskType) {….} |
TaskInProgress.java中主要函數定義如下:
1
|
boolean canBeSpeculated( long currentTime){…} |
原創文章,轉載請註明: 轉載自董的博客
本文鏈接地址: http://dongxicheng.org/mapreduce/hadoop-speculative-task/