dr.elephant啟發式演算法詳解
Metrics測量指標
1. Used Resources
Job使用資源的數量,單位是:GB Hours
計算方式
我們將任務的資源使用定義為:所有mapper任務和所有reducer任務的資源使用的總和。
例如:
有如下的job:
4 mappers with runtime {12, 15, 20, 30} mins.
4 reducers with runtime {10 , 12, 15, 18} mins.
向yarn申請的容器大小為:4 GB
那麼,
所有mapper使用的資源: 4 * (( 12 + 15 + 20 + 30 ) / 60 ) GB Hours = 5.133 GB Hours
所有reducer使用的資源: 4 * (( 10 + 12 + 15 + 18 ) / 60 ) GB Hours = 3.666 GB Hours
Job使用的總資源= 5.133 + 3.6666 = 8.799 GB Hours
2.Wasted Resources
資源浪費就是指資源浪費的數量,我們通過GB
hours或者百分比方式展示job浪費資源的數量。
計算方式
為了計算資源的浪費情況,我們需要先計算下面的指標:
1)Map和reduce任務中浪費的最小的記憶體大小
2)Map和reduce任務的執行時間
任務浪費的最小的記憶體大小= 申請的yarn容器的大小- 所有的任務中最大使用的記憶體大小
任務浪費的資源= 任務浪費的最小記憶體大小* 任務執行的時間,
job總的資源浪費 = 所有的任務浪費的資源總和
對於每一個任務我們定義如下:
peak_memory_used := task使用的記憶體上界
runtime := task執行時長
通過所有task中的最大使用的實體記憶體(max_physical_memory)和虛擬記憶體(virtual_memory)可以計算出任意task的peak_memory_used,又由於每個任務的上界通過max_physical_memory來確定,因此我們可以說每個任務的peak_memory_used可以通過下面的公式計算出來:
peak_memory_used = Max(max_physical_memory, virtual_memory/2.1)
其中2.1是叢集的記憶體因子(該引數yarn.nodemanager.vmem-pmem-ratio對應的值)
每個task的最小記憶體浪費可以通過下面的公式計算:
wasted_memory = container_size - peak_memory_used
每個任務的最小資源浪費可以通過下面的公式計算:
wasted_resource = wasted_memory * runtime
總的資源的浪費情況就等於所有任務的wasted_resource的總和
3.Runtime
執行時間指標展示作業總的執行時間。
計算方式
Job的執行時間是通過job的完成時間減去job提交到yarn的資源管理器的時間計算出來的。
例如:
Job的開始時間是:1461837302868 ms
Job的完成時間是:1461840952182 ms
Job的執行時間是:1461840952182 - 1461837302868= 3649314 ms or 1.01 hours
4.Wait time
Job的等待時間是指job執行中花費在等待狀態總的時間。
計算方式
對於每一個job我們定義如下的名詞:
ideal_start_time := 所有任務都應該完成啟動的理想的時間
finish_time := 任務完成時間
task_runtime := 任務執行時間
- Map tasks
對於map任務,我們定義如下:
ideal_start_time := job的開始時間
我們找出所有map任務中最長執行時間(task_runtime_max)和最後的完成時間( finish_time_last ),那麼job中mapper的總的等待時間就可以通過如下的公式計算出來:
mapper_wait_time = finish_time_last - (ideal_start_time + task_runtime_max)
- Reduce tasks
對於reducer任務,我們定義如下:
ideal_start_time := 通過獲取的reducer慢開始的百分比(mapreduce.job.reduce.slowstart.completedmaps:這個引數的含義是,當Map Task完成的比例達到該值後才會為Reduce Task申請資源,預設是0.05)並找到map任務完成之後最先開始的那個reducer,就可以計算出該引數
我們找到reducer任務最大執行時間( task_runtime_max)和最後完成的時間( finish_time_last )
那麼job的reducer任務的總等待時間就可以使用如下公式計算出來:
reducer_wait_time =finish_time_last - (ideal_start_time + task_runtime_max)
total_wait_time = mapper_wait_time + reducer_wait_time
例如:
如上圖:
對於map任務:
ideal_start_time = t1
task_runtime_max = Map_1對應的執行時間
finish_time_last = t4
mapper_wait_time = t4 – Map_1對應的執行時間– t1
對於reduce任務:
ideal_start_time = t2
task_runtime_max = Reduce_3對應的執行時間
finish_time_last = t6
reducer_wait_time = t6 -
Reduce_3對應的執行時間- t2
總的等待時間:
total_wait_time =mapper_wait_time + reducer_wait_time
MapReduce演算法分析
1.Mapper資料傾斜
資料進入到Mapper作業中後,有可能會發生資料的傾斜,這種資料傾斜主要是考慮到HDFS檔案大小差別太大導致的。
1)判斷依據
根據每個map task執行的時間和資料量兩個指標進行判定。
2)原理
Mapper資料傾斜啟發式演算法(mapper
data skew heuristic)會將所有的Mapper分成兩部分,其中一部分的所有作業(task)的平均資料量會大於另一部分的平均資料量,之後根據這兩個組的平均資料量的差值的絕對值/這兩組資料中平均資料量的最小值來判斷資料傾斜程度。時間方面的傾斜程度演算法一樣。
此圖中的A和B兩組的平均資料量和平均執行時間都差不多,沒有發生資料傾斜
此圖中A和B兩組的平均執行時間差不多,但是平均資料量差別很大,最終導致嚴重程度為Critical,這說明該作業讀取的hdfs中的資料檔案大小差別太大,1)可能是有很多小檔案, 2)也可能是檔案大小超過block大小的10%以上一點,導致超出的部分又佔用了一個block
3)計算步驟
(1)遞迴的計算作業輸入資料量的平均值,然後根據作業的輸入量平均值將所有的作業分成兩組Group_A 和Group_B。
(2)計算各組的平均值,並求出資料量小的組的平均值(minAvg)和兩組平均值之差的絕對值(diffAvgAbs)
(3)求出誤差( diffAvgAbs/ minAvg ),根據誤差和給定的誤差級別(比如:{2, 4, 8, 16})計算嚴重程度severity
(4)計算出資料量小的那組的的task數量,並根據配置的task數量級別(比如:{10, 50, 100, 200})計算出task數量的嚴重程度taskSeverity
(5)取資料量大的那組的平均資料量,並根據配置的檔案大小級別(比如:{1d / 8, 1d / 4, 1d / 2, 1d}其中的每個值需要乘以block的大小)計算出task資料量的嚴重程度fileSeverity
(6)求出上面計算出來的嚴重程度的最小值作為map 資料傾斜程度的結果。
2.Mapper GC
Mapper GC會分析任務的GC效率。它會計算出所有mapper的平均GC時間佔平均CPU時間的比例。避免打擾使用者,該演算法在程式碼中設定了很寬鬆的範圍(觀察線上跑的結果發現確實沒有GC報警的情況),但是如果分析的結果仍然報警的話,說明你的程式碼確實需要優化了。
1)判斷依據
平均GC時間佔平均CPU時間的比例,比例越高,嚴重程度越大,通常來說程式碼需要優化。
2)原理
計算出所有作業的平均的CPU使用時間、平均執行時間以及平均GC的時間。我們要計算Mapper GC嚴重度的最小值,這個值可以通過平均執行時間和平均垃圾回收時間佔平均CPU總消耗時間的比例來計算。
3)計算步驟
(1)計算出平均CPU使用時間(avgCPU)、平均執行時間(avgRuntime)、平均GC時間(avgGC)。
(2)計算出平均GC時間佔平均CPU時間的比例(gcRatio)
(3)使用gcRatio和誤差級別(比如:{0.01d, 0.02d, 0.03d, 0.04d})計算嚴重程度gcSeverity
(4)使用平均執行時間和執行時間的級別(比如:{5, 10, 12, 15} 單位:分鐘數)計算執行時間的嚴重程度runtimeSeverity
(5)取上面兩個嚴重程度的最小值作為gc的嚴重程度。
3.Mapper的記憶體消耗
分析每個Mapper實際記憶體的消耗,並檢查作業消耗的記憶體比例以及向yarn申請的容器的總記憶體,該指標用於分析使用者申請的容器記憶體是否合理,比如:你申請了10G的yarn容器的記憶體,但是實際消耗記憶體卻只有1G,說明你的任務浪費了很多記憶體資源,此時就會顯示嚴重級別為critical,說明你需要減少每個mapper向yarn容器申請的記憶體資源的大小。
1)判斷依據
task任務平均使用記憶體佔向yarn容器所申請的記憶體的比例。比例越低說明記憶體資源浪費程度越高,需要優化,反之則說明資源利用率越高越好。
2)原理
計算平均記憶體消耗佔用向yarn資源容器申請的記憶體大小比率,使用該比率結合設定的記憶體利用率級別判斷mapper對記憶體的消耗是否合理。
此圖對記憶體的消耗就不合理,因為申請的記憶體高達24G,但是實際使用的記憶體最大卻只有6G左右,平均記憶體使用才3.7G左右,嚴重浪費記憶體資源。
3)計算步驟
(1)計算所有task的平均實體記憶體消耗(avgPhysicalMemory)、平均虛擬記憶體消耗(avgVirtualMemory)、平均執行時間(avgRuntime),並從該應用的配置檔案中獲取向yarn容器申請的記憶體大小(containerMemory)
(2)計算平均實體記憶體消耗(avgPhysicalMemory)和向yarn容器申請的記憶體大小(containerMemory)的比值(ratio)。
(3)使用上面的比值(ratio)結合記憶體利用率級別(比如:{0.6d, 0.5d, 0.4d, 0.3d}),計算出嚴重程度severity。
(4)再使用向yarn容器申請的記憶體大小(containerMemory)與容器級別(比如:{1.1d,
1.5d, 2.0d, 2.5d} 中的每一個值需要乘以yarn的配置檔案中配置的預設的容器大小)計算出申請的容器的嚴重程度containerSeverity
(5)計算出上面兩個嚴重級別的最小值作為記憶體消耗的嚴重級別
4.Mapper的執行速度
分析Mapper程式碼的執行效率。通過這些分析可以知道mapper屬於CPU消耗型的,或者是mapper處理的資料量過大。通過這個能夠分析出mapper執行速度快慢和處理的資料量大小之間的關係。
1)判斷依據
所有task的執行速度的中值作為判斷mapper執行速度的依據,而執行速度是通過每個task的輸入資料/執行時長得到的。
2)原理
通過計算每個task的執行速度的中值,結合配置的磁碟的讀取速度,判斷出mapper任務的執行速度,但是需要排除執行時間過短導致的錯誤的結果。
此任務執行速度就太慢了,也可以推斷出該任務是CPU消耗型任務。
3)計算步驟
(1)計算出執行速度的中值(medianSpeed)、執行時間的中值(medianRuntime)、輸入資料量的中值(medianDataSize)
(2)使用執行速度中值(medianSpeed)結合執行速度的級別(比如:{1d / 2, 1d / 4, 1d / 8, 1d / 32} 每個值需要乘以磁碟的讀取速度,預設100M/s)計算出嚴重級別speedSeverity。
(3)再使用執行時間的中值(medianRuntime)結合執行時間級別(比如:{5, 10, 15, 30})計算出執行時間的嚴重程度runtimeSeverity
(4)取speedSeverity和runtimeSeverity兩個嚴重級別的較小者作為執行速度的嚴重級別。
5.Mapper溢位
該演算法從磁碟IO的角度去評測mapper的效能。mapper溢位比例(溢位的記錄數/總輸出的記錄數)是衡量mapper效能的一個重要指標:如果這個值接近2,表示幾乎每個記錄都溢位了,並臨時寫到磁碟兩次(其中一次發生在記憶體排序快取溢位時,另一次發生在歸併排序所有溢位的切換時)。當這些發生時表明mapper輸入輸出的資料量過大了。
1)判斷依據
總的溢位記錄數和總的輸出記錄數的比值。
2)原理
計算出所有task的溢位記錄數和所有task的輸出記錄數的比值,使用該比值進行mapper溢位嚴重程度的判斷,該比值越大說明輸入輸出的資料量過大,需要進行優化以提高執行速度。
3)計算步驟
(1)計算出所有task的總的溢位記錄數(totalSpillRecords)、總的輸出記錄數(totalOutputRecords),並計算出其比值(ratioSpill)
(2)使用上面計算的比值結合配置的溢位級別(比如:{2.01d, 2.2d, 2.5d, 3.0d})計算出溢位的嚴重程度spillSeverity。
(3)根據task的數量計算出任務數的嚴重程度taskNumberSeverity
(4)取上面兩個小的嚴重程度作為溢位嚴重程度。
6.Mapper執行時間
這部分分析mappers的數量是否合適。通過分析結果,我們可以更好的優化任務中mapper的數量這個引數的設定。有以下兩種情況發生時,這個引數的優化就顯得很迫切了:
1)Mapper的執行時間很短,可能的原因如下:
mapper的數量過多
mapper的平均執行時間很短
檔案尺寸太小
2)Mapper的執行時間很長,可能的原因包括:
mapper的數量很少
mapper的平均執行時間很長
檔案的大小過大(個別檔案是GB級別)
根據所有task執行的平均時長進行嚴重程度的判斷
2)原理
首先計算出所有task的平均執行時間,之後根據該平均執行時間計算出最短和最長的任務執行時長嚴重級別,取兩個嚴重級別中較大的作為執行時長的嚴重級別。
3)計算步驟
(1)計算出所有task的平均輸入大小(avgInputSize)、平均執行時長(avgRuntime)(2)根據平均執行時長(avgRuntime)結合短執行時長級別(比如:{10, 4, 2, 1} 其中的每個值代表的是分鐘數)計算出短執行時長的嚴重級別shortSeverity
(3)根據任務數結合任務數的級別(比如:{50, 101, 500, 1000})計算出任務數的嚴重程度taskNumberSeverity
(4)取上面shortSeverity和taskNumberSeverity的較小值作為短執行時長的嚴重級別realShortSeverity
(5)根據平均執行時長(avgRuntime)結合長執行時長級別(比如:{15, 30, 60, 120} 其中的每個值代表的是分鐘數)計算出長執行時長的嚴重級別longSeverity
(6)取realShortSeverity和longSeverity總的較大則作為執行時長的嚴重級別
7.Reducer資料傾斜
分析進入到每個Reduce中的資料是否有傾斜。該分析能夠發現Reducer中是否存在這種情況,將Reduce分為兩部分,其中一部分的輸入資料量明顯大於另一部分的輸入資料量。
1)判斷依據
根據每個reduce task執行的時間和資料量兩個指標進行判定。
2)原理
Mapper資料傾斜啟發式演算法(reducer
data skew heuristic)會將所有的Reducer分成兩部分,其中一部分的所有作業(task)的平均資料量會大於另一部分的平均資料量,之後根據這兩個組的平均資料量的差值/這兩組資料中平均資料量的最小值來判斷資料傾斜程度。時間方面的傾斜程度演算法一樣。
3)計算步驟
(1)遞迴的計算作業輸入資料量的平均值,然後根據作業的輸入量平均值將所有的作業分成兩組Group_A 和Group_B。
(2)計算各組的平均值,並求出資料量小的組的平均值(minAvg)和兩組平均值之差的絕對值(diffAvgAbs)
(3)求出誤差( diffAvgAbs/ minAvg ),根據誤差和給定的誤差級別(比如:{2, 4, 8, 16})計算嚴重程度severity
(4)計算出資料量小的那組的的task數量,並根據配置的task數量級別(比如:{10, 50, 100, 200})計算出task數量的嚴重程度taskSeverity
(5)取資料量大的那組的平均資料量,並根據配置的檔案大小級別(比如:{1d / 8, 1d / 4, 1d / 2, 1d}其中的每個值需要乘以block的大小)計算出task資料量的嚴重程度fileSeverity
(6)求出上面計算出來的嚴重程度的最小值作為map 資料傾斜程度的結果。
8.Reducer GC
Reduce GC用於分析任務的GC效率,能夠計算並告訴我們GC時間佔所用CPU時間的比例。該演算法在程式碼中設定了很寬鬆的範圍,避免打擾使用者,但是如果分析的結果任然報警的話,說明你的程式碼確實需要優化了。
1)判斷依據
平均GC時間佔平均CPU時間的比例,比例越高,嚴重程度越大,通常來說程式碼需要優化。
2)原理
首先,會計算出所有任務的平均CPU消耗時間、平均執行時間以及平均垃圾回收所消耗的時間。然後,演算法會根據平均執行時間以及垃圾回收時間佔平均CPU時間的比值來計算出最低的嚴重度。
3)計算步驟
(1)計算出平均CPU使用時間(avgCPU)、平均執行時間(avgRuntime)、平均GC時間(avgGC)。
(2)計算出平均GC時間佔平均CPU時間的比例(gcRatio)
(3)使用gcRatio和誤差級別(比如:{0.01d, 0.02d, 0.03d, 0.04d})計算嚴重程度gcSeverity
(4)使用平均執行時間和執行時間的級別(比如:{5, 10, 12, 15} 單位:分鐘數)計算執行時間的嚴重程度runtimeSeverity
(5)取上面兩個嚴重程度的最小值作為gc的嚴重程度。
9.Reducer記憶體消耗
分析每個Reducer實際記憶體的消耗,並檢查作業消耗的記憶體比例以及向yarn申請的容器的總記憶體,該指標用於分析使用者申請的容器記憶體是否合理,比如:你申請了10G的yarn容器的記憶體,但是實際消耗記憶體卻只有1G,說明你的任務浪費了很多記憶體資源,此時就會顯示嚴重級別為critical,說明你需要減少每個Reducer向yarn容器申請的記憶體資源的大小。
1)判斷依據
task任務平均使用記憶體佔向yarn容器所申請的記憶體的比例。比例越低說明記憶體資源浪費程度越高,需要優化,反之則說明資源利用率越高越好。
2)原理
計算平均記憶體消耗佔用向yarn資源容器申請的記憶體大小比率,使用該比率結合設定的記憶體利用率級別判斷reducer對記憶體的消耗是否合理。
此圖對記憶體的消耗就不合理,因為申請的記憶體高達24G,但是實際使用的記憶體最大卻只有6G左右,平均記憶體使用才3.7G左右,嚴重浪費記憶體資源。
3)計算步驟
(1)計算所有task的平均實體記憶體消耗(avgPhysicalMemory)、平均虛擬記憶體消耗(avgVirtualMemory)、平均執行時間(avgRuntime),並從該應用的配置檔案中獲取向yarn容器申請的記憶體大小(containerMemory)。
(2)計算平均實體記憶體消耗(avgPhysicalMemory)和向yarn容器申請的記憶體大小(containerMemory)的比值(ratio)。
(3)使用上面的比值(ratio)結合記憶體利用率級別(比如:{0.6d, 0.5d, 0.4d, 0.3d}),計算出嚴重程度severity。
(4)再使用向yarn容器申請的記憶體大小(containerMemory)與容器級別(比如:{1.1d,
1.5d, 2.0d, 2.5d} 中的每一個值需要乘以yarn的配置檔案中配置的預設的容器大小)計算出申請的容器的嚴重程度containerSeverity 。
(5)計算出上面兩個嚴重級別的最小值作為記憶體消耗的嚴重級別。
10.Reducer時間
這部分分析Reducer的執行效率,可以幫助我們更好的配置任務中reducer的數量;當出現以下兩種情況時,說明Reducer的數量需要進行調優:
1)Reducer過多,hadoop任務可能的表現是:
Reducer數量過多
Reducer的執行時間很短
2)Reducer過少,hadoop任務可能的表現是:
Reducer數量過少
Reducer執行時間很長
1)判斷依據
根據所有task執行的平均時長進行嚴重程度的判斷
2)原理
首先計算出所有task的平均執行時間,之後根據該平均執行時間計算出最短和最長的任務執行時長嚴重級別,取兩個嚴重級別中較大的作為執行時長的嚴重級別。
任務數多,執行時長過短,屬於嚴重級別的
執行時長計算:屬於嚴重級別的
任務數方面計算:屬於None級別的
取上面兩個級別的較小者None級別作為最終的嚴重級別。
3)計算步驟
(1)計算出所有task的最大執行時長(minRuntime)、最小執行時長(maxRuntime)、平均執行時長(avgRuntime)(2)根據平均執行時長(avgRuntime)結合短執行時長級別(比如:{10, 4, 2, 1} 單位:分鐘)計算出短執行時長的嚴重級別shortSeverity
(3)根據任務數結合任務數的級別(比如:{50, 101, 500, 1000})計算出任務數的嚴重程度taskNumberSeverity
(4)取上面shortSeverity和taskNumberSeverity的較小值作為短執行時長的嚴重級別realShortSeverity
(5)根據平均執行時長(avgRuntime)結合長執行時長級別(比如:{15, 30, 60, 120}單位:分鐘數)計算出長執行時長的嚴重級別longSeverity
(6)取realShortSeverity和longSeverity總的較大則作為執行時長的嚴重級別
11.洗牌和排序
分析reducer消耗的總時間以及reducer在進行洗牌和排序時消耗的時間,通過這些分析,可以判斷reducer的執行效率。
1)判斷依據
所有task的平均shuffle時長和平均sort時長進行判斷的,取兩者中較大的作為洗牌和排序的嚴重級別
2)原理
首先計算出所有的task的平均shuffle時長和平均sort時長,之後再分別與平均執行時長(totalTime - shuffleTime - sortTime)進行相除,計算出shuffle和sort的嚴重級別,取兩者中較大的作為洗牌和排序的嚴重級別。
其中後面的X代表倍數的意思,計算方式是:avgShuffleTime / avgCodeTime 和avgSortTime /
avgCodeTime。
此圖顯示shuffle的時間很長,但是sort的時間很短,說明你需要調整slowstart引數"mapreduce.job.reduce.slowstart.completedmaps"從0.90 調大一些,要小於1.0。但是需要注意的是,調整此引數可以降低shuffle的時間,但是可能會增加整個job的執行時間。
3)計算步驟
(1)計算出所有task的平均執行時長(avgExecuteTime)、平均shuffle時長(avgShuffleTime)、平均sort時長(avgSortTime)
(2)將平均shuffle時長結合執行時長的級別(比如:{1, 5, 10, 30} 單位:分鐘數)計算出shuffle的嚴重級別shuffleSeverity
(3)計算shuffleRatio = avgShuffleTime* 2 / avgExecuteTime,之後使用shuffleRatio結合執行比率級別(比如:{1, 2, 4, 8})計算出shuffle執行比率級別shuffleRatioSeverity
(4)取shuffleSeverity 和shuffleRatioSeverity的較小者作為真正的shuffle嚴重級別realShuffleSeverity
(5)將平均sort時長(avgSortTime)結合執行時長的級別(比如:{1, 5, 10, 30}單位:分鐘數)計算出sort的嚴重級別sortSeverity
(6)計算sortRatio = avgSortTime * 2 /avgExecuteTime,之後使用sortRatio結合執行比率級別(比如:{1, 2, 4, 8})計算出sort執行比率級別sortRatioSeverity
(7)取sortSeverity和sortRatioSeverity的最小值作為真正的shuffle嚴重級別realSortSeverity
(8)取realShuffleSeverity和realSortSeverity中較大者作為洗牌和排序的嚴重級別