Dataproc动态分配与静态分配中的Spark作业

时间:2019-03-04 21:23:57

标签: apache-spark spark-streaming yarn google-cloud-dataproc

我有一个Dataproc集群:

master-6cores | 32克

worker {0-7}-6cores | 32克

最大分配:内存:24576,vCores:6

要提交两个火花流作业,一个接一个

首先,我尝试使用默认配置spark.dynamicAllocation.enabled=true

提交

在30%的情况下,我看到第一个作业几乎捕获了所有可用的内存,第二个排队,等待了一段时间。 (这是一项流式作业,每批次占用一小部分资源。)

我的第二个尝试是更改动态分配。我提交了具有相同配置的相同两个作业:

spark.dynamicAllocation.enabled=false
spark.executor.memory=12g
spark.executor.cores=3
spark.executor.instances=6
spark.driver.memory=8g

令人惊讶的是,在Yarn UI中我看到了:

第一个作业的7个具有84g内存分配的运行容器

3个正在运行的容器,它们的内存分配为36g,保留内存为72g ,用于第二项工作

在Spark UI 中,第一项工作有6个执行者和驱动程序,第二项工作有2个执行者和驱动程序

在没有动态分配和相同配置的情况下重试(删除先前的作业并提交相同的作业)后,我得到了完全不同的结果:

5个容器,两个作业59g内存分配,第二个作业 71g保留内存。在spark UI中,我在这两种情况下都看到4个执行程序和驱动程序。

我有几个问题:

  1. 如果dynamicAllocation = false ,为什么纱线容器的数量是 与执行人的数量不同? (首先我以为 额外的纱线容器是驱动程序,但内存有所不同。)
  2. 如果dynamicAllocation = false ,为什么Yarn不会按我的方式创建容器 确切要求-两个作业都需要6个容器(火花执行器)。为什么使用相同配置进行两次不同的尝试会导致不同的结果?
  3. 如果dynamicAllocation = true -低耗内存火花作业将如何控制所有纱线资源

谢谢

2 个答案:

答案 0 :(得分:4)

Spark和YARN调度非常混乱。我将以相反的顺序回答问题:

3)您不应该在Spark流作业中使用动态分配。

问题在于,只要有待执行的任务积压,Spark就会不断向YARN请求更多执行者。一旦Spark作业获得执行者,它将一直保留到执行者空闲1分钟(当然是可配置的)为止。在批处理作业中,这是可以的,因为通常会有大量连续的任务积压。

但是,在流作业中,每个微批处理的开始都有大量的任务,但是执行者实际上大部分时间都是空闲的。因此,流式作业将吸引很多不需要的执行器。

要解决此问题,旧的流API(DStreams)具有自己的动态分配版本:https://issues.apache.org/jira/browse/SPARK-12133。此JIRA具有更多的背景知识,说明了Spark的批处理动态分配算法为何不适合流式传输。

但是,Spark结构化流(可能正在使用的内容)不支持动态分配:https://issues.apache.org/jira/browse/SPARK-24815

tl; dr Spark根据任务积压而不是使用的内存来请求执行者。

1&2)@Vamshi T是正确的。每个YARN应用程序都有一个“ Application Master”,它负责为该应用程序请求容器。您的每个Spark作业都有一个应用程序母版,可以代理来自驱动程序的容器请求。

您的配置似乎与您在YARN中看到的不匹配,所以不确定那里发生了什么。您有8名工人,每人给了YARN 24克。对于12g执行程序,每个节点应该有2个执行程序,总共有16个“插槽”。一个应用程序主控+ 6个执行程序每个应用程序应为7个容器,因此两个应用程序均应适合16个插槽。

我们将App Master配置为具有更少的内存,这就是为什么应用程序的总内存不是12g的整数倍。

如果您希望两个应用程序同时调度其所有执行程序,则应设置spark.executor.instances = 5。

假设您正在使用结构化流,还可以在同一个Spark应用程序中运行两个流作业(从驱动程序上的不同线程提交它们)。

有用的参考文献:

答案 1 :(得分:1)

在我的经历中,我也注意到了类似的行为,这就是我观察到的。首先,纱线的资源分配取决于提交作业时群集上的可用资源。当使用相同配置几乎同时提交两个作业时,yarn将在两个作业之间平均分配可用资源。现在,当您将动态分配加入混合时,事情会变得有些混乱/复杂。现在,您的情况如下:

第一个作业的7个运行容器的内存分配为84g。 -您有7个容器,因为您请求了6个执行者,每个执行者一个容器,另外一个容器用于应用程序Master

3个正在运行的容器,它们的内存分配为36g,第二个作业的保留内存为72g -自从第二份工作在一段时间后提交以来,Yarn分配了剩余的资源... 2个容器,每个执行器一个,另外一个用于您的应用程序主。

您的容器将永远不会与您请求的执行器匹配,并且总是比您请求的执行器多一个,因为您需要一个容器来运行应用程序主服务器。

希望能回答部分问题。