我正在运行一个包含一些非常大的阶段(例如 >20k 任务)的 Spark 作业,并使用 1k 到 2k 执行器运行它。
在某些情况下,阶段似乎运行不稳定:随着时间的推移,许多可用的执行器变得空闲,尽管仍然处于有许多未完成任务的阶段中间。从用户的角度来看,任务似乎正在完成,但已完成给定任务的执行者不会获得分配给他们的新任务。结果,该阶段花费的时间比应有的时间长,并且大量执行器 CPU 时间浪费在空闲上。这似乎主要(仅?)发生在从 HDFS 读取数据的输入阶段。
不稳定期间的 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]
在什么情况下会发生这种情况,我该如何避免这种行为?
注意:我正在使用动态分配,但我很确定这与这个问题无关——例如,在不稳定时期,在 Spark 应用程序主 UI 中,我可以看到预期的执行器数量是“活动的”,但是没有运行“活动任务”。
当每个任务花费的时间非常少时,我在 Spark 中看到过这样的行为。由于某种原因,调度程序似乎假设作业将更快地完成,而无需额外的分配开销,因为每个任务都完成得如此之快。
有几点值得尝试:
- Try
.coalesce()
减少分区的数量,以便每个分区需要更长的时间来运行(当然,这可能会导致洗牌步骤,并可能增加总体作业
时间,你必须实验)
- 调整
spark.locality.wait*
设置here https://spark.apache.org/docs/latest/configuration.html#scheduling。如果每个任务花费的时间少于默认等待时间3s
,那么调度程序可能只是试图保持现有插槽已满,而永远没有机会分配更多插槽。
我还没有追查到exactly是什么导致了这个问题,所以这些只是基于我自己在我自己的(小得多的)集群中的观察的猜测和预感。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)