注意:以下翻译的准确性尚未经过验证。这是使用 AIP ↗ 从原始英文文本进行的机器翻译。

理解 Spark 细节

Apache Spark ↗ 是 Foundry 数据集成层中最常用的执行引擎。为了理解管道的性能特征并找到优化的方法,了解代码在 Spark 中的执行细节是很重要的。Foundry 提供了集成工具,帮助您查看和理解任务在 Spark 中的性能。此页面概述了可用的 Spark 细节,并提供了关于这些细节的含义的指导。

获取 Spark 细节

对于在 Foundry 中搭建的任何数据集,按照以下步骤查看 Spark 细节:

  1. 查看搭建报告
    • 数据集预览或从数据沿袭中,选择历史标签,选择列表中的单个搭建,然后选择查看搭建报告
    • 所有搭建的视图中,只需选择列表中的一个搭建。
  2. 选择一个任务。一个搭建由一个或多个任务组成,显示在甘特图下方的列表中。从列表中选择一个任务,然后选择Spark 细节按钮:

查看 spark 细节

Spark 细节页面提供有关任务在 Spark 中执行的信息。对于每个任务,Spark 细节页面在各种类别中显示信息,如下所示:

Spark 细节标签

概览标签

概览标签提供了关于一个任务的以下信息:

高层次任务指标

  • 所有任务的总运行时间: 所有阶段中所有任务的运行时间之和
  • 任务持续时间: Spark 计算的持续时间(从第一个阶段开始到最后一个阶段完成的时间)

通过这两个指标,您可以计算并行比率为

所有任务的总运行时间 / 任务持续时间

接近 1 的比率表示并行性较差。

  • 磁盘溢出: 从执行器的 RAM 移动到磁盘的数据大小,跨所有阶段。

    • 当数据无法适应执行器的内存时会发生这种情况。读写磁盘是一个慢操作,因此如果任务溢出,它将显著变慢。偶尔,根据正在发生的计算类型,溢出可能会导致执行器内存不足并导致任务失败。
    • 请注意,对于大型数据集,磁盘溢出是预期的。
  • Shuffle 写: 在任务期间跨所有阶段已被 shuffle 的数据量。

    • Shuffle 是数据在 Spark 阶段之间和跨分区移动的过程;例如,计算合并(当没有表被广播时)、执行聚合或应用重新分区。
    • 由于 shuffle 导致网络 IO 和磁盘 IO,因此它可以占据任务运行时间的很大一部分。
    • 因此,编写高效 Spark 任务的一个关键目标是最小化 shuffle;例如,通过确保可以广播的合并实际上正在被广播,通过利用数据集的分桶在下游任务中可能经常在相同键上合并或聚合(以避免此数据集的下游 shuffle),或通过避免不必要的重新分区步骤。

阶段执行时间线和阶段间依赖关系

在任务开始时,Spark 解释变换的代码以创建执行计划,可以表示为具有相互依赖关系的一组阶段。下图显示了阶段的执行时间线。

搭建应用阶段时间线

最左侧的阶段通常表示输入的加载,而最右侧的阶段通常表示输出的写入。在上述示例中,阶段 28、30、31、32、33 和 35 需要很长时间执行,因此它们是优化此任务运行时间的良好候选者。

阶段 28、30、31、33 和 35 可以并行运行,这意味着它们没有相互依赖关系。然而,阶段 32 只有在所有先前阶段完成后才能开始,这意味着:

  • 减少阶段 35 的运行时间不会带来任何显著的改进,因为等待时间由 max_runtime(28, 30, 31, 33, 35) 主导。因此,要看到明显的改进,所有这些阶段都需要加速。
  • 阶段 32 是任务的瓶颈,因为它占总任务持续时间的约 35%。

任务并发图

任务并发图有助于理解资源的使用情况。它绘制了阶段随时间的并发性。与任务并发类似,阶段并发可以计算为:

阶段中任务的总运行时间 / 阶段持续时间

任务并发图的时间轴与上方阶段的甘特图共享,以便于识别相关性。

搭建应用任务并发时间线

在上述图表中,阶段 32 的并发性几乎为 1。这意味着这个阶段中几乎所有的工作都在一个(非常长的)任务中进行,表明计算没有被分布。

一个完美分布的任务看起来像这样: 搭建应用任务并发完美分布

阶段细节

在尝试理解为何某个阶段失败或缓慢时,获取更多信息可能是有用的。不幸的是,自动追踪阶段正在做的事情回到原始代码甚至物理计划目前是不可能的,因为 Spark 在将代码转换为阶段时不公开这种沿袭。

阶段概览仍然允许对失败或长时间运行的阶段进行一些调查: 搭建应用阶段细节倾斜

一半的任务用时不到 2 秒,但更有趣的是最大运行时间。一个任务占用阶段总运行时间的约 63%。这与先前图表中的观察结果一致,表明这个阶段是瓶颈,并且几乎所有的工作都发生在一个任务中。

要了解更多信息,可以跳转到阶段细节: 搭建应用任务细节倾斜

这显示了在此阶段运行的一些任务的示例,以及与阶段本身相关的指标。

任务 22267-0 用时 1小时16分,因此是最慢的一个。确实,该任务处理了 81M 行,而其他任务处理了 10K-700K 行。此倾斜的症状是:

  • 高磁盘溢出:190GB vs 其他任务为 0
  • 高执行器峰值内存:4.5GB vs 其他任务为 1GB

执行器标签

执行器

执行器标签捕获来自 Spark 任务的驱动或执行器的某些指标,包括堆栈跟踪和内存直方图。这些指标在调试 Spark 任务的性能问题时很有用。

选择快照按钮可以捕获来自正在运行任务的 Java 堆栈跟踪或仅驱动内存直方图。任务必须处于运行状态(如果任务已完成,这些指标将不再可供收集)。

堆栈跟踪是一种查看 Spark 任务的每个线程此刻正在执行什么的方法。例如,如果一个任务似乎挂起(即,在预期时没有进展),进行堆栈跟踪可能会揭示当时正在执行的内容。

内存直方图显示 Java Object 的数量及其在堆内存中的大小(以字节为单位)。它在理解内存使用情况和调试内存相关问题时很有用。

请注意,获取指标可能会影响运行任务的性能。收集这些指标是 JVM 需要完成的额外工作。例如,获取内存直方图会触发垃圾回收。