我有一个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个执行程序和驱动程序。
我有几个问题:
谢谢
答案 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个容器,每个执行器一个,另外一个用于您的应用程序主。
您的容器将永远不会与您请求的执行器匹配,并且总是比您请求的执行器多一个,因为您需要一个容器来运行应用程序主服务器。
希望能回答部分问题。