Dataproc 动态与静态分配中的 Spark 作业
Spark job in Dataproc dynamic vs static allocation
我有一个 Dataproc 集群:
master - 6cores| 32克
工人{0-7} - 6 核| 32克
最大分配:memory:24576、vCores:6
有两个 spark-streaming 作业要提交,一个接一个
首先,我尝试使用默认配置提交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 个执行程序和驱动程序。
我有几个问题:
- 如果dynamicAllocation=false,为什么yarn容器的数量是
与执行者的数量不同? (一开始我以为
additional yarn container 是一个驱动程序,但它在内存中有所不同。)
- 如果dynamicAllocation=false,为什么我的Yarn不创建容器
确切要求 - 两个作业的 6 个容器(火花执行器)。为什么使用相同配置的两次不同尝试会导致不同的结果?
- 如果 dynamicAllocation=true - 低消耗内存 spark 作业怎么可能控制所有 Yarn 资源
谢谢
我在我的经历中也注意到了类似的行为,这是我观察到的。首先,yarn 的资源分配取决于作业提交时集群上的可用资源。当两个作业几乎同时提交并具有相同的配置时,yarn 会在作业之间平均分配可用资源。现在,当您将动态分配加入其中时,事情变得有点 confusing/complex。现在你的情况如下:
7 运行 个容器,第一个作业分配了 84g 内存。
--你有7个容器,因为你请求了6个executor,每个executor一个容器,另外一个容器给应用程序Master
3 运行 个容器,为第二个作业分配了 36g 内存和 72g 预留内存
-- 由于第二个作业在一段时间后提交,Yarn 分配了剩余的资源...2 个容器,每个执行器一个,另外一个给你的应用程序主机。
您的容器永远不会与您请求的执行器数量匹配,并且总是比您请求的执行器数量多一个,因为您需要一个容器才能 运行 您的应用程序主机。
希望这能回答您的部分问题。
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 个工人,给 YARN 分配了 24g。使用 12g 执行器,每个节点应该有 2 个执行器,总共 16 "slots"。一个 app master + 6 个执行器应该是每个应用程序有 7 个容器,所以两个应用程序都应该适合 16 个插槽。
我们将 app master 配置为具有更少的内存,这就是为什么应用程序的总内存不是 12g 的干净倍数的原因。
如果您希望两个应用程序同时安排它们的所有执行程序,您应该设置 spark.executor.instances=5。
假设您正在使用结构化流,您也可以 运行 同一 Spark 应用程序中的两个流作业(从驱动程序上的不同线程提交它们)。
有用的参考资料:
我有一个 Dataproc 集群:
master - 6cores| 32克
工人{0-7} - 6 核| 32克
最大分配:memory:24576、vCores:6
有两个 spark-streaming 作业要提交,一个接一个
首先,我尝试使用默认配置提交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 个执行程序和驱动程序。
我有几个问题:
- 如果dynamicAllocation=false,为什么yarn容器的数量是 与执行者的数量不同? (一开始我以为 additional yarn container 是一个驱动程序,但它在内存中有所不同。)
- 如果dynamicAllocation=false,为什么我的Yarn不创建容器 确切要求 - 两个作业的 6 个容器(火花执行器)。为什么使用相同配置的两次不同尝试会导致不同的结果?
- 如果 dynamicAllocation=true - 低消耗内存 spark 作业怎么可能控制所有 Yarn 资源
谢谢
我在我的经历中也注意到了类似的行为,这是我观察到的。首先,yarn 的资源分配取决于作业提交时集群上的可用资源。当两个作业几乎同时提交并具有相同的配置时,yarn 会在作业之间平均分配可用资源。现在,当您将动态分配加入其中时,事情变得有点 confusing/complex。现在你的情况如下:
7 运行 个容器,第一个作业分配了 84g 内存。 --你有7个容器,因为你请求了6个executor,每个executor一个容器,另外一个容器给应用程序Master
3 运行 个容器,为第二个作业分配了 36g 内存和 72g 预留内存 -- 由于第二个作业在一段时间后提交,Yarn 分配了剩余的资源...2 个容器,每个执行器一个,另外一个给你的应用程序主机。
您的容器永远不会与您请求的执行器数量匹配,并且总是比您请求的执行器数量多一个,因为您需要一个容器才能 运行 您的应用程序主机。
希望这能回答您的部分问题。
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 个工人,给 YARN 分配了 24g。使用 12g 执行器,每个节点应该有 2 个执行器,总共 16 "slots"。一个 app master + 6 个执行器应该是每个应用程序有 7 个容器,所以两个应用程序都应该适合 16 个插槽。
我们将 app master 配置为具有更少的内存,这就是为什么应用程序的总内存不是 12g 的干净倍数的原因。
如果您希望两个应用程序同时安排它们的所有执行程序,您应该设置 spark.executor.instances=5。
假设您正在使用结构化流,您也可以 运行 同一 Spark 应用程序中的两个流作业(从驱动程序上的不同线程提交它们)。
有用的参考资料: