EMR 忽略 Spark 提交参数(内存/核心/等)

Mir*_*nor 7 amazon-web-services amazon-emr apache-spark

我正在尝试使用 EMR 集群上的所有资源。

集群本身是 4 台 m4.4xlarge 机器(1 个驱动程序和 3 个工作程序),具有 16 个 vCore、64 GiB 内存、EBS 存储:128 GiB

通过 cli 启动集群时,我会看到以下选项(所有 3 个选项都在同一数据管道中执行):

只需使用“maximizeResourceAllocation”,无需任何其他 Spark-submit 参数

这只给了我这里介绍的 2 个执行者 在此输入图像描述

不要放置任何东西,让 Spark-defaults 完成他们的工作

提供以下低质量的执行者 在此输入图像描述

使用 AWS 指南了解如何在 EMR 中配置集群

按照本指南,我推导出以下spark-submit参数:

      "--conf",
      "spark.executor.cores=5",
      "--conf",
      "spark.executor.memory=18g",
      "--conf",
      "spark.executor.memoryOverhead=3g",
      "--conf",
      "spark.executor.instances=9",

      "--conf",
      "spark.driver.cores=5",
      "--conf",
      "spark.driver.memory=18g",

      "--conf",
      "spark.default.parallelism=45",

      "--conf",
      "spark.sql.shuffle.partitions=45",

Run Code Online (Sandbox Code Playgroud)

但仍然没有运气: 在此输入图像描述

现在,我确实在互联网上查找了 所有可以查找的地方,但找不到任何关于为什么 EMR 不使用所提供的所有资源的解释。也许我遗漏了一些东西,或者也许这是预期的行为,但是当“maximizeAllocation”仅跨越具有 3 个工作线程的集群上的 2 个执行程序时,就会出现问题。

更新:

因此,今天在运行不同的数据管道时,我使用“maximizeResourceAllocation”得到了这个: 在此输入图像描述 这比其他的要好得多,但在使用的内存和执行器方面仍然缺乏很多(尽管EMR团队的有人说emr将执行器合并为超级执行器以提高性能)。

m_v*_*uri 1

我想添加我的答案,尽管我无法解释您所看到的所有案例。

但我会尽力解释那些我能做到的。

案例1:最大资源分配

这是 Amazon EMR 特定配置,我不完全确定 Amazon EMR 在此配置中的底层功能。

当您启用 maximizeResourceAllocation 时,EMR 会计算核心实例组中实例上的执行程序可用的最大计算和内存资源。然后根据计算出的最大值设置相应的 Spark-defaults 设置

上面的文本片段来自这里

看起来集群可能有一些配置,并且 EMR 会为此计算资源分配。但我并不完全确定。

我想知道的一个后续问题是您的集群上是否正在运行其他应用程序?这可以改变 EMR 确定资源分配的计算方式。

情况 2:默认值

我可以解释一下。

这是使用DynamicResourceAllocationSpark 中称为的东西。来自火花网站

Spark 提供了一种机制,可以根据工作负载动态调整应用程序占用的资源。这意味着,如果不再使用资源,您的应用程序可能会将资源返还给集群,并在以后有需求时再次请求它们。如果多个应用程序共享 Spark 集群中的资源,则此功能特别有用。

查看上面的链接,它提到 Amazon EMR 使用动态资源分配作为 Spark 的默认设置。

因此,您看到的执行程序大小和计数是由您正在运行的工作负载决定的。

案例 3:特定值

要理解这里的分配,需要了解Spark的内存分配模型。

Spark 执行器和驱动程序作为 JVM 运行。他们将 JVM 的内存分为

  1. On-Heap Space,进一步分为
    • 存储内存- 用于缓存数据
    • 执行内存- 临时存储用于洗牌、连接排序的数据
    • 用户内存- 用于 RDD 转换和依赖图
    • 保留内存- 用于 Spark 内部对象
  2. 堆外空间- 通常默认禁用

堆上空间的内存分配如下:

X = Executor Memory Configured
X' = X - 300MB (for reserved memory - taken to start of with to let spark work)

User Memory = X' * 0.40 = User Memory
Storage + Execution Memory = X' * 0.60

The Storage and execution memory is split 50-50.
Run Code Online (Sandbox Code Playgroud)

对于你的例子

X  = 18 GB ~ 18000 MB
X' = 18000 - 300 MB = 17700 MB = Remaining

User = 17700 * 0.40 = 7080
Storage + Execution = 17700 * 0.60 = 10620 ~ 10 GB
And that is what you're seeing in your Storage Memory column and On-heap storage memory column.

Note2: the boundary between Storage and Execution space is flexible. If required, storage could evict all of execution and vice-versa.
Run Code Online (Sandbox Code Playgroud)

代入数字,它似乎与您的观察结果一致。这就解释了为什么你最初分配的 18G 中只得到了 10G。

希望这能让您看到的至少两个案例更加清晰。