我有一个Dataproc集群:
master - 6cores | 32克
工人{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个执行器和驱动程序。
我有一些问题:
谢谢
Spark和YARN调度非常混乱。我将以相反的顺序回答问题:
3)您不应该在Spark流工作中使用动态分配。
问题是,只要有大量的任务要运行,Spark就会不断要求YARN提供更多的执行程序。一旦Spark作业获得执行程序,它就会保留它直到执行程序空闲1分钟(当然可配置)。在批处理作业中,这是可以的,因为通常会有大量连续积压的任务。
但是,在流媒体作业中,每个微批处理开始时都会出现一系列任务,但执行程序在大多数情况下实际上处于空闲状态。因此,流媒体作业将抓住许多不需要的执行者。
为了解决这个问题,旧的流API(DStreams)有自己的动态分配版本:https://issues.apache.org/jira/browse/SPARK-12133。这个JIRA有更多背景知道为什么Spark的批量动态分配算法不适合流式传输。
但是,Spark Structured Streaming(可能是您正在使用的)不支持动态分配:https://issues.apache.org/jira/browse/SPARK-24815。
tl; dr Spark根据其任务积压请求执行程序,而不是基于使用的内存。
1&2)@Vamshi T是对的。每个YARN应用程序都有一个“Application Master”,它负责为应用程序请求容器。每个Spark作业都有一个app master,用于代理驱动程序对容器的请求。
您的配置似乎与您在YARN中看到的不匹配,因此不确定那里发生了什么。你有8名工人,24克给了YARN。使用12g执行程序,每个节点应该有2个执行程序,总共16个“插槽”。应用程序主机+6个执行程序应该是每个应用程序7个容器,因此两个应用程序应该适合16个插槽。
我们将app master配置为具有更少的内存,这就是为什么应用程序的总内存不是12g的干净倍数的原因。
如果您希望两个应用程序同时安排所有执行程序,则应设置spark.executor.instances = 5。
假设您正在使用结构化流,您也可以在同一个Spark应用程序中运行两个流作业(从驱动程序的不同线程提交它们)。
有用的参考:
我也注意到了我的经历中的类似行为,这是我观察到的。首先,纱线的资源分配取决于提交作业时群集上的可用资源。当两个作业几乎同时以相同的配置提交时,yarn会在作业之间平均分配可用资源。现在,当您将动态分配投入到混合中时,事情变得有点混乱/复杂。现在在你的情况下:
7个运行容器,为第一个作业分配84g内存。 - 你有7个容器,因为你要求6个执行器,每个执行器有一个容器,额外的一个容器用于应用程序Master
3个运行容器具有36g内存分配和72g预留内存用于第二个作业 - 由于第二个作业在一段时间后提交,Yarn分配了剩余资源... 2个容器,每个执行器一个,另外一个用于应用程序主机。
您的容器永远不会与您请求的执行程序匹配,并且总是比您请求的执行程序数多一个,因为您需要一个容器来运行您的应用程序主机。
希望能回答你的部分问题。