

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 了解 Amazon EMR 节点分配策略和场景
<a name="managed-scaling-allocation-strategy"></a>

本部分概述了可用于 Amazon EMR 托管扩展的节点分配策略和常见扩展方案。

## 节点分配策略
<a name="node-allocation-strategy"></a>

Amazon EMR 托管扩展基于以下纵向扩展和缩减策略分配核心节点和任务节点：

**纵向扩展策略 **
+ 对于 Amazon EMR 7.2 及更高版本，托管扩展首先根据节点标签和应用程序进程限制 YARN 属性来添加节点。
+ 对于 Amazon EMR 7.2 及更高版本，如果启用了节点标签并将应用程序进程限制在 `CORE` 节点上，则在应用程序进程需求增加和执行程序需求增加时，Amazon EMR 托管式自动扩缩功能会增加核心节点和任务节点。同样地，如果启用了节点标签并将应用程序进程限制在 `ON_DEMAND` 节点上，则托管扩展会在应用程序进程需求增加时扩展按需型节点，并在执行程序需求增加时扩展竞价型节点。
+ 如果未启用节点标签，则应用程序进程放置不限于任何节点或市场类型。
+ 通过使用节点标签，托管扩展可在同一调整大小操作中纵向扩展和缩减不同的实例组和实例集。例如，在 `instance_group1` 具有 `ON_DEMAND` 节点和 `instance_group2` 具有 `SPOT` 节点的场景中，启用了节点标签，应用程序进程仅限于带有 `ON_DEMAND` 标签的节点。如果应用程序进程需求减少，而执行程序需求增加，则托管扩展将缩减 `instance_group1` 并纵向扩展 `instance_group2`。
+ 当 Amazon EMR 在纵向扩展当前实例组的过程中遇到延迟时，使用托管式扩展的集群会自动切换到不同的任务实例组。
+ 如果设置了 `MaximumCoreCapacityUnits` 参数，则 Amazon EMR 会扩展核心节点，直到核心单位达到所允许的最大限制。所有剩余容量都添加到任务节点。
+ 如果设置了 `MaximumOnDemandCapacityUnits` 参数，则 Amazon EMR 使用按需型实例扩展集群，直到按需型单位达到所允许的最大限制。使用竞价型实例添加所有剩余容量。
+ 如果同时设置了 `MaximumCoreCapacityUnits` 和 `MaximumOnDemandCapacityUnits` 参数，Amazon EMR 在扩展期间会考虑这两个限制。

  例如，如果 `MaximumCoreCapacityUnits` 小于 `MaximumOnDemandCapacityUnits`，Amazon EMR 首先扩展核心节点，直到达到核心容量限制。对于剩余容量，Amazon EMR 首先使用按需型实例扩展任务节点，直到达到按需型限制，然后对任务节点使用竞价型实例。

**缩减策略**
+ 与纵向扩展策略类似，Amazon EMR 会根据节点标签删除节点。有关节点标签的更多信息，请参阅[了解节点类型：主节点、核心节点和任务节点](https://docs.amazonaws.cn/emr/latest/ManagementGuide/emr-master-core-task-nodes.html)。
+ 如果您尚未启用节点标签，托管扩展将删除任务节点，然后删除核心节点，直到达到所需的缩减目标容量。托管扩展绝不会将集群缩减到托管扩展策略中指定的最小限制以下。
+ Amazon EMR 版本 5.34.0 及更高版本以及 Amazon EMR 版本 6.4.0 及更高版本支持 Spark 随机排序数据感知，这可以防止实例在托管扩展感知到现有随机排序数据时缩减。有关随机排序操作的更多信息，请参阅 [Spark 编程指南](https://spark.apache.org/docs/latest/rdd-programming-guide.html#shuffle-operations)。托管扩展会尽最大努力防止使用任何活跃 Spark 应用程序当前和上一阶段的随机排序数据缩减节点，最长不超过 30 分钟。这有助于最大限度地减少随机排序数据意外丢失，从而避免重新尝试作业和重新计算中间数据。但是，并不能保证防止随机排序数据丢失。为了改进 Spark 随机播放保护，我们建议对版本标签为 7.4 或更高版本的集群进行洗牌感知。在集群配置中添加以下标志，以启用改进的 Spark shuffle 保护。
  + 如果`yarn.nodemanager.shuffledata-monitor.interval-ms`标志（默认 30000 毫秒）或`spark.dynamicAllocation.executorIdleTimeout`（默认 60 秒）已更改为默认值，请`true`通过更新必要的标志来确保条件`spark.dynamicAllocation.executorIdleTimeout > yarn.nodemanager.shuffledata-monitor.interval-ms`保持不变。

    ```
    [
    	{
    		"Classification": "yarn-site",
    		"Properties": { 
    		"yarn.resourcemanager.decommissioning-nodes-watcher.wait-for-shuffle-data": "true"
    		}
    	},
    	{
    		"Classification": "spark-defaults",
    		"Properties": {
    		"spark.dynamicAllocation.enabled": "true",
    		"spark.shuffle.service.removeShuffle": "true"
    		}
    	}
    ]
    ```
+ 托管扩展首先删除任务节点，然后删除核心节点，直到达到所需的缩减目标容量。集群的扩展绝不会低于托管扩展策略中指定的最小限制。
+ 对于使用 Amazon EMR 5.x 版本 5.34.0 及更高版本以及 6.x 版本 6.4.0 及更高版本启动的集群，如果在 Apache Spark 上运行的应用程序中有活动阶段，Amazon EMR 托管扩展不会缩小`ApplicationMaster`适用于 Apache Spark 的节点。这样可以最大限度地减少任务失败和重试次数，这有助于提高作业性能并降低成本。要确认集群中哪些节点正在运行 `ApplicationMaster`，请访问 Spark 历史记录服务器，然后在 Spark 应用程序 ID 的**执行程序**选项卡下筛选驱动程序。
+ 虽然使用 EMR 托管扩展进行智能扩展可最大限度地减少 Spark 的随机排序数据丢失，但是在某些情况下，在缩减期间可能无法保护瞬态随机排序数据。为了增强缩减期间随机排序数据的弹性，建议在 YARN 中启用**随机排序数据正常停用**。在 YARN 中启用**随机排序数据正常停用**后，选择进行缩减且具有随机排序数据的节点将进入**停用**状态并继续提供随机排序文件。YARN 会 ResourceManager 等到节点报告不存在随机文件，然后再从集群中移除节点。
  + Amazon EMR 6.11.0 及更高版本支持 Tez 和 Shuffle Handlers 的 **Hive** 洗牌数据基于 Yarn 的优雅停用。 MapReduce 
    + 通过将 `yarn.resourcemanager.decommissioning-nodes-watcher.wait-for-shuffle-data` 设置为 `true` 来启用随机排序数据正常停用。
  + 启用外部随机排序服务后（EMR on EC2 中默认启用），Amazon EMR 7.4.0 及更高版本支持基于 Yarn 的 Spark 随机排序数据正常停用。
    + 在 Yarn 上运行 Spark 时，Spark 外部随机播放服务的默认行为是 Yarn NodeManager 在应用程序终止时删除应用程序的洗牌文件。这可能会影响节点停用速度和计算利用率。对于长时间运行的应用程序，请考虑将 `spark.shuffle.service.removeShuffle` 设置为 `true` 以移除不再使用的随机排序文件，从而更快地停用没有活跃随机排序数据的节点。
  + 为了最大限度地减少 Amazon EMR 7.4.0 及更高版本中的 Spark shuffle 数据丢失，请考虑设置以下标志。
    + 如果`yarn.nodemanager.shuffledata-monitor.interval-ms`标志（默认 30000 毫秒）或`spark.dynamicAllocation.executorIdleTimeout`（默认 60 秒）已更改为默认值，请`true`通过更新必要的标志来确保条件`spark.dynamicAllocation.executorIdleTimeout > yarn.nodemanager.shuffledata-monitor.interval-ms`保持不变。

      ```
      [
      	{
      		"Classification": "yarn-site",
      		"Properties": { 
      		"yarn.resourcemanager.decommissioning-nodes-watcher.wait-for-shuffle-data": "true"
      		}
      	},
      	{
      		"Classification": "spark-defaults",
      		"Properties": {
      		"spark.dynamicAllocation.enabled": "true",
      		"spark.shuffle.service.removeShuffle": "true"
      		}
      	}
      ]
      ```

如果集群没有任何负载，Amazon EMR 将取消在之前评估中添加的新实例，并执行缩减操作 如果集群负载过重，Amazon EMR 会取消移除实例，并执行纵向扩展操作。

## 节点分配注意事项
<a name="node-allocation-considerations"></a>

我们建议您对核心节点使用按需型购买选项，以避免在竞价型实例回收时丢失 HDFS 数据。当更多竞价型实例添加到任务节点时，您可以使用任务节点的竞价型购买选项来降低成本并加快任务执行速度。

## 节点分配方案
<a name="node-allocation-scenarios"></a>

您可以通过设置不同组合的最大、最小、按需限制和最大核心节点参数，根据您的需求创建各种扩展方案。

**方案 1: 仅扩展核心节点**

要仅扩展核心节点，托管式扩展参数必须满足以下要求：
+ 按需限制等于最大边界。
+ 最大核心节点等于最大边界。

当未指定按需限制和最大核心节点参数时，这两个参数都默认为最大边界。

如果您在节点标签中使用托管扩展，并将应用程序进程限制为仅在 `CORE` 节点上运行，那么这种情况就不适用，因为托管扩展会扩展任务节点以满足执行程序的需求。

以下示例仅演示了扩展核心节点的方案。


<table>
<thead>
  <tr><th>集群初始状态</th><th>扩展参数</th><th>扩展行为</th></tr>
</thead>
<tbody>
  <tr><td>**实例组**<br />核心：1 个按需型<br />任务：1 个按需型和 1 个竞价型</td><td>`UnitType`: Instances<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：20 <br />`MaximumCoreCapacityUnits`：20</td><td rowspan="2">使用按需型在核心节点上扩展 1 到 20 个实例或实例集单元。在任务节点上没有扩展。<br />如果您在节点标签中使用托管扩展，并将应用程序进程限制在 `ON_DEMAND` 节点上，集群将在使用 `On-Demand` 或 `Spot` 类型的 `CORE` 节点上扩展 1 到 20 个实例或实例集单位，具体取决于需求类型。</td></tr>
  <tr><td>**实例机群**<br />核心：1 个按需型<br />任务：1 个按需型和 1 个竞价型</td><td>UnitType: InstanceFleetUnits<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：20 <br />`MaximumCoreCapacityUnits`：20</td></tr>
</tbody>
</table>


**方案 2：仅扩展任务节点 **

要仅扩展任务节点，托管扩展参数必须满足以下要求：
+ 最大核心节点必须等于最小边界。

以下示例仅演示了扩展任务节点的方案。


<table>
<thead>
  <tr><th>集群初始状态</th><th>扩展参数</th><th>扩展行为</th></tr>
</thead>
<tbody>
  <tr><td>**实例组**<br />核心：2 个按需型<br />任务：1 个竞价型</td><td>`UnitType`: Instances<br />`MinimumCapacityUnits`：2<br />`MaximumCapacityUnits`：20<br />`MaximumCoreCapacityUnits`：2</td><td rowspan="2">保持核心节点稳定在 2 个，并且仅在 0 到 18 个实例或实例集单位之间扩展任务节点。最小边界和最大边界之间的容量仅添加到任务节点。<br /> 如果您在节点标签中使用托管扩展，并将应用程序进程限制在 ON\_DEMAND 节点上，集群的核心节点将稳定在 2 个，仅在使用 `On-demand` 或 `Spot` 类型的 0 到 18 个实例或实例集单位之间扩展任务节点，具体取决于需求类型。</td></tr>
  <tr><td>**实例机群**<br />核心：2 个按需型<br />任务：1 个竞价型</td><td>`UnitType`: InstanceFleetUnits<br />`MinimumCapacityUnits`：2<br />`MaximumCapacityUnits`：20<br />`MaximumCoreCapacityUnits`：2</td></tr>
</tbody>
</table>


**方案 3：集群中仅有按需型实例 **

要仅拥有按需型实例，您的集群和托管扩展参数必须满足以下要求：
+ 按需限制等于最大边界。

  当未指定按需限制时，参数值默认为最大边界。默认值表示 Amazon EMR 仅扩展按需型实例。

如果最大核心节点小于最大边界，则可以使用最大核心节点参数来分配核心节点和任务节点之间的容量。

要在由实例组组成的集群中启用此方案，集群中的所有节点组必须在初始配置期间使用按需市场类型。

如果您在节点标签中使用托管扩展，并将应用程序进程限制为仅在 `ON_DEMAND` 节点上运行，那么这种情况就不适用，因为托管扩展会扩展 `Spot` 节点以满足执行程序的需求。

以下示例演示了在整个集群中使用按需型实例的方案。


<table>
<thead>
  <tr><th>集群初始状态</th><th>扩展参数</th><th>扩展行为</th></tr>
</thead>
<tbody>
  <tr><td>**实例组**<br />核心：1 个按需型<br />任务：1 个按需 </td><td>`UnitType`: Instances<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：20 <br />`MaximumCoreCapacityUnits`：12</td><td rowspan="2">使用按需类型在核心节点上扩展 1 到 12 个实例或实例集单位。在任务节点上使用按需扩展剩余容量。不使用竞价型实例进行扩展。<br /> 如果您在节点标签中使用托管扩展，并将应用程序进程限制在 `CORE` 节点上，集群将在使用 `ON_DEMAND` 类型的 `CORE` 节点或 `task` 节点上扩展 1 到 20 个实例或实例集单位，具体取决于需求类型。核心节点上的扩展不会超过 12 个实例或实例集单位。</td></tr>
  <tr><td>**实例机群**<br />核心：1 个按需型<br />任务：1 个按需</td><td>`UnitType`: InstanceFleetUnits<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：20 <br />`MaximumCoreCapacityUnits`：12</td></tr>
</tbody>
</table>


**方案 4: 集群中只有竞价型实例**

要仅拥有竞价型实例，托管扩展参数必须满足以下要求：
+ 按需限制设置为 0。

如果最大核心节点小于最大边界，则可以使用最大核心节点参数来分配核心节点和任务节点之间的容量。

要在由实例组组成的集群中启用此方案，核心实例组必须在初始配置期间使用竞价型购买选项。如果任务实例组中没有竞价型实例，则 Amazon EMR 托管扩展会在需要时使用竞价型实例创建任务组。

如果您在节点标签中使用托管扩展，并将应用程序进程限制为仅在 `ON_DEMAND` 节点上运行，那么这种情况就不适用，因为托管扩展会扩展 `ON_DEMAND` 节点以满足应用程序进程的需求。

以下示例演示了在整个集群中使用竞价型实例的方案。


<table>
<thead>
  <tr><th>集群初始状态</th><th>扩展参数</th><th>扩展行为</th></tr>
</thead>
<tbody>
  <tr><td>**实例组**<br />核心：1 个 Spot<br />任务：1 个竞价型</td><td>`UnitType`: Instances<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：0</td><td rowspan="2">使用 Spot 在核心节点上扩展 1 到 20 个实例或实例集单位。不使用按需类型进行扩展。<br />如果您在节点标签中使用托管扩展，并将应用程序进程限制在 `CORE` 节点上，集群将在使用竞价型的 `CORE` 或 `TASK` 节点上扩展 1 到 20 个实例或实例集单位，具体取决于需求类型。Amazon EMR 不会使用 `ON_DEMAND` 类型进行扩展。</td></tr>
  <tr><td>**实例机群**<br />核心：1 个 Spot<br />任务：1 个竞价型</td><td>`UnitType`: InstanceFleetUnits<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：0</td></tr>
</tbody>
</table>


**方案 5：在核心节点上扩展按需型实例，在任务节点上扩展 Spot 实例 **

要在核心节点上扩展按需型实例和在任务节点上扩展 Spot 实例，托管扩展参数必须满足以下要求：
+ 按需限制必须等于最大核心节点。
+ 按需限制和最大核心节点必须小于最大边界。

要在由实例组组成的集群中启用此方案，核心节点组必须使用按需购买选项。

如果您在节点标签中使用托管扩展，并将应用程序进程限制为仅在 `ON_DEMAND` 节点或 `CORE` 节点上运行，那么这种情况就不适用。

以下示例演示了在核心节点上扩展按需型实例和在任务节点上扩展竞价型实例的方案。


<table>
<thead>
  <tr><th>集群初始状态</th><th>扩展参数</th><th>扩展行为</th></tr>
</thead>
<tbody>
  <tr><td>**实例组**<br />核心：1 个按需型<br />任务：1 个按需型和 1 个竞价型</td><td>`UnitType`: Instances<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：7 <br />`MaximumCoreCapacityUnits`：7</td><td rowspan="2">由于任务节点上已有 1 个按需单位且按需最大限制为 7，请在核心节点上纵向扩展到 6 个按需单位。。然后在任务节点上纵向扩展到 13 个竞价型单位。</td></tr>
  <tr><td>**实例机群**<br />核心：1 个按需型<br />任务：1 个按需型和 1 个竞价型</td><td>`UnitType`: InstanceFleetUnits<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：7<br />`MaximumCoreCapacityUnits`：7</td></tr>
</tbody>
</table>


**场景 6：根据应用程序进程需求扩展 `CORE` 实例，根据执行程序需求扩展 `TASK` 实例。**

只有当您在节点标签中使用托管扩展，并将应用程序进程限制为仅在 `CORE` 节点上运行，这种情况才适用。

要根据应用程序进程需求扩展 `CORE` 节点，根据执行程序需求扩展 `TASK` 节点，必须在集群启动时设置以下配置：
+  `yarn.node-labels.enabled:true` 
+  `yarn.node-labels.am.default-node-label-expression: 'CORE'` 

当未指定 `ON_DEMAND` 限制和最大 `CORE` 节点参数时，这两个参数都默认为最大边界。

如果最大 `ON_DEMAND` 节点小于最大边界，托管扩展将使用最大 `ON_DEMAND` 节点参数在 `ON_DEMAND` 和 `SPOT` 节点之间拆分容量分配。如果将最大 `CORE` 节点参数设置为小于或等于最小容量参数，则 `CORE` 节点在最大核心容量下保持静态。

以下示例演示了根据应用进程需求扩展 CORE 实例和根据执行程序需求扩展 TASK 实例的场景。


<table>
<thead>
  <tr><th>集群初始状态</th><th>扩展参数</th><th>扩展行为</th></tr>
</thead>
<tbody>
  <tr><td>**实例组**<br />核心：1 个按需型<br />任务：1 个按需</td><td>`UnitType`: Instances<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`: 10<br />`MaximumCoreCapacityUnits`：20</td><td rowspan="2">根据集群的应用程序进程需求在 1 到 20 个节点之间扩展 `CORE` 节点，取决于使用的是按需型或竞价型。在 Amazon EMR 分配 `CORE` 节点后，根据执行程序需求和剩余可用容量扩展 `TASK` 节点。<br />请求的 `CORE` 和 `TASK` 节点总和不会超过 20 的 `maximumCapacity`。请求的按需型核心节点和按需型任务节点的总和不会超过 10 的 `maximumOnDemandCapacity`。其他核心或任务节点使用竞价型。</td></tr>
  <tr><td>**实例机群**<br />核心：1 个按需型<br />任务：1 个按需</td><td>`UnitType`: InstanceFleetUnits<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`: 10<br />`MaximumCoreCapacityUnits`：20</td></tr>
</tbody>
</table>


**场景 7：根据应用程序进程需求扩展 `ON_DEMAND` 实例，根据执行程序需求扩展 `SPOT` 实例。**

只有当您在节点标签中使用托管扩展，并将应用程序进程限制为仅在 `ON_DEMAND` 节点上运行，这种情况才适用。

要根据应用程序进程需求扩展 `ON_DEMAND` 节点，根据执行程序需求扩展 `SPOT` 节点，必须在集群启动时设置以下配置：
+  `yarn.node-labels.enabled:true` 
+  `yarn.node-labels.am.default-node-label-expression: 'ON_DEMAND'` 

当未指定 `ON_DEMAND` 限制和最大 `CORE` 节点参数时，这两个参数都默认为最大边界。

如果最大 `CORE` 节点小于最大边界，托管扩展将使用最大 `CORE` 节点参数在 `CORE` 和 `TASK` 节点之间拆分容量分配。如果将最大 `CORE` 节点参数设置为小于或等于最小容量参数，则 `CORE` 节点在最大核心容量下保持静态。

以下示例演示了根据应用进程需求扩展按需型实例和根据执行程序需求扩展竞价型实例的场景。


<table>
<thead>
  <tr><th>集群初始状态</th><th>扩展参数</th><th>扩展行为</th></tr>
</thead>
<tbody>
  <tr><td>**实例组**<br />核心：1 个按需型<br />任务：1 个按需</td><td>`UnitType`: Instances<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：20<br />`MaximumCoreCapacityUnits`: 10</td><td rowspan="2">根据集群的应用程序进程需求在 1 到 20 个节点之间扩展 `ON_DEMAND` 节点，取决于使用的是 `CORE` 或 `TASK` 节点类型。在 Amazon EMR 分配 `ON_DEMAND` 节点后，根据执行程序需求和剩余可用容量扩展 `SPOT` 节点。<br />请求的 `ON_DEMAND` 和 `SPOT` 节点总和不会超过 20 的 `maximumCapacity`。请求的按需型核心节点和竞价型任务节点的总和不会超过 10 的 `maximumCoreCapacity`。其他按需型或竞价型节点使用 `TASK` 节点类型。</td></tr>
  <tr><td>**实例机群**<br />核心：1 个按需型<br />任务：1 个按需</td><td>`UnitType`: InstanceFleetUnits<br />`MinimumCapacityUnits`：1<br />`MaximumCapacityUnits`：20<br />`MaximumOnDemandCapacityUnits`：20<br />`MaximumCoreCapacityUnits`: 10</td></tr>
</tbody>
</table>
