我正在执行一些非常大的阶段的Spark任务(例如> 20k个任务),并使用1k到2k的执行程序来运行它。
在某些情况下,一个阶段似乎运行不稳定:随着时间的推移,许多可用的执行器变得闲置,尽管它们仍处于许多未完成任务的中间。从用户的角度看,任务似乎正在完成,但是完成给定任务的执行者不会获得分配给他们的新任务。结果,该阶段花费的时间超过了原本应有的时间,并且空闲时浪费了很多执行器CPU时间。
Spark stderr日志在不稳定时期的示例-请注意,随着时间的流逝,正在运行的任务数量逐渐减少,直到几乎达到零,然后突然跳回> 1k个正在运行的任务:
[Stage 0:==============================> (17979 + 1070) / 28504]
[Stage 0:==============================> (18042 + 1019) / 28504]
[Stage 0:===============================> (18140 + 921) / 28504]
[Stage 0:===============================> (18222 + 842) / 28504]
[Stage 0:===============================> (18263 + 803) / 28504]
[Stage 0:===============================> (18282 + 786) / 28504]
[Stage 0:===============================> (18320 + 751) / 28504]
[Stage 0:===============================> (18566 + 508) / 28504]
[Stage 0:================================> (18791 + 284) / 28504]
[Stage 0:================================> (18897 + 176) / 28504]
[Stage 0:================================> (18940 + 134) / 28504]
[Stage 0:================================> (18972 + 107) / 28504]
[Stage 0:=================================> (19035 + 47) / 28504]
[Stage 0:=================================> (19067 + 17) / 28504]
[Stage 0:================================> (19075 + 1070) / 28504]
[Stage 0:================================> (19107 + 1039) / 28504]
[Stage 0:================================> (19165 + 982) / 28504]
[Stage 0:=================================> (19212 + 937) / 28504]
[Stage 0:=================================> (19251 + 899) / 28504]
[Stage 0:=================================> (19355 + 831) / 28504]
[Stage 0:=================================> (19481 + 708) / 28504]
这是阶段稳定运行时stderr的样子-正在运行的任务数量大致保持不变,因为新任务在执行者完成之前的任务时会分配给他们:
[Stage 1:===================> (11599 + 2043) / 28504]
[Stage 1:===================> (11620 + 2042) / 28504]
[Stage 1:===================> (11656 + 2044) / 28504]
[Stage 1:===================> (11692 + 2045) / 28504]
[Stage 1:===================> (11714 + 2045) / 28504]
[Stage 1:===================> (11741 + 2047) / 28504]
[Stage 1:===================> (11771 + 2047) / 28504]
[Stage 1:===================> (11818 + 2047) / 28504]
在什么情况下会发生这种情况,我该如何避免这种行为?
NB:我正在使用动态分配,但是我很确定这与该问题无关-例如,在不稳定时期,在Spark Application Master UI中,我可以看到预期的执行器数量为“活动” ”,但未运行“活动任务”。
答案 0 :(得分:1)
当每个任务花费的时间很短时,我从火花中看到了这样的行为。由于某些原因,调度程序似乎认为该作业将完成得更快而没有额外的分发开销,因为每个任务都完成得如此之快。
要尝试的几件事:
.coalesce()
减少分区数量,以使每个分区都需要更长的运行时间(当然,这可能会导致洗牌,并可能增加总体工作量)
时间,您将不得不试用)spark.locality.wait*
设置here。如果每个任务所花费的时间少于默认的等待时间3s
,则调度程序可能只是试图保持现有插槽已满,而再也没有机会分配更多的插槽。我还没有找到确切的原因是什么原因,因此,这些只是基于我对自己(更小)集群的观察得出的推测和预感。