创建自定义弹性伸缩策略

当您的业务量需求不断波动,并且您对自己的业务有较好的了解,建议您开启弹性伸缩功能并配置相应的伸缩规则,E-MapReduce(简称 EMR)能够根据业务量的变化自动增加或减少Task节点,从而确保顺利完成作业并节省成本。本文为您介绍如何配置自定义弹性伸缩策略。

前提条件

  • 已创建数据湖(DataLake)、实时数据流(DataFlow)、数据分析(OLAP)、数据服务(DataServing)或自定义场景(Custom)的集群,详情请参见创建集群

  • 已在集群中创建了按量付费或者抢占式实例的Task节点组,详情请参见新增节点组

使用限制

  • 为避免由于ECS库存不足造成的弹性伸缩失败,您可以在新增节点组时配置多种实例规格,最多可以选择10ECS实例规格作为备选,系统将按照您选择的顺序购买实例。每个节点创建时,会从第一个规格开始尝试,如果该规格库存不足,则依次尝试下一个规格,直到创建成功。最终购买的实例规格可能随库存变化而不同。

  • 仅部署了YARN服务的集群,支持配置负载伸缩规则。

注意事项

  • 您可以为满足条件的节点组添加弹性伸缩规则,当规则触发后,节点组会按照规则预置的策略自动进行节点组的扩容或缩容。如果不设置规则,则不会触发弹性伸缩活动。

  • 系统会根据您选择的具体实例规格,自动匹配出满足条件的实例,并显示在备选实例列表中。您需要选中备选的实例,以便集群按照已选的实例规格进行伸缩。

说明

如果您设置了多条弹性伸缩规则,当同时满足条件时,系统将会按照以下内容触发和执行:

  • 扩容规则优先于缩容规则。

  • 按时间和按负载规则按照触发先后执行。

  • 按负载伸缩中根据触发的指标的时间排序。

  • 按负载伸缩中同一触发指标按照规则创建的顺序触发。

操作步骤

方式一:为已有集群创建自定义伸缩规则

  1. 进入弹性伸缩页面。

    1. 登录EMR on ECS

    2. 在顶部菜单栏处,根据实际情况选择地域和资源组

    3. 单击目标集群的集群名称。

    4. 单击上方的弹性伸缩

  2. 配置伸缩规则。

    1. 弹性伸缩配置页签的配置弹性伸缩规则区域,单击自定义弹性伸缩规则,选择重新配置,单击目标节点组操作列的编辑

    2. 配置弹性伸缩面板,配置相关参数,单击确定

      • 当前节点组实例数限制:用于控制组内节点数,避免弹性伸缩自动运行时导致节点组内节点数过多或过少。如果需要更改该配置,请单击修改限制

        • 最大实例数:用于控制当前节点组的节点数量上限,当到达上限时,不再扩容。

        • 最小实例数:用于控制当前节点组的节点数量下限,当到达下限时,不再缩容。

      • 触发规则:展示和配置当前节点组的伸缩规则。

        • 规定时间伸缩

          如果集群计算量在一定的周期内存在明显的波峰和波谷,则您可以设置在每天、每周或每月的固定时间段扩展一定量的Task节点来补充计算能力,这样在保证作业完成的同时,也可以节省成本。伸缩规则分为扩容规则和缩容规则。

          重要

          为了避免潜在的操作冲突以及确保伸缩操作能够顺利进行,请勿将扩容与缩容规则的执行时间设定为同一时间点。

          本示例以扩容规则为例介绍。

          参数

          描述

          扩容类型

          按时间扩容。

          规则名称

          在同一个集群中,伸缩规则名称(包括扩容规则和缩容规则)不允许重复。

          执行频率

          • 重复执行:您可以选择每天、每周或每月的某一特定时间点执行一次弹性伸缩动作。

          • 只执行一次:集群在指定的时间点执行一次弹性伸缩动作。

          执行时间

          选择规则执行的时间。

          规则有效期

          执行频率选择重复执行时,可设置规则生效的截止时间,超出后则不会触发伸缩活动。

          重试过期时间

          弹性伸缩在到达指定时间时可能由于各种原因不能执行,通过设置重试过期时间,系统会在该时间范围内每隔30秒尝试执行一次,直到满足条件时执行伸缩。设置范围为0~3600秒。

          例如,在指定时间段需要进行弹性伸缩动作A,如果有其他弹性伸缩动作B正在执行或正处在冷却期,则动作A无法执行。在您设置的重试过期时间内,每隔30秒会重试一次,尝试执行A,一旦条件满足,集群会立刻执行弹性伸缩。

          单次扩容数

          时间规则被触发时,节点组每次触发伸缩活动增加的节点数量。

          尽力交付

          建议开启。开启尽力交付功能后,会按照最大成功数量交付,以维持整体业务的顺畅运行。

          例如,配置在每天零点定时扩容100台,如果库存只有90台,未开启该流程会失败,开启以后,会将90台库存进行交付。

        • 规定负载伸缩

          说明

          仅当创建的集群部署了YARN服务后,才支持该功能。

          如果您无法准确地预估大数据计算的波峰和波谷,但对自己的业务模式有较好的了解,则可以使用按负载伸缩配置的策略。伸缩规则分为扩容规则和缩容规则,本示例以扩容规则为例介绍。

          参数

          描述

          扩容类型

          按负载扩容。

          规则名称

          在同一个集群中,伸缩规则名称(包括扩容规则和缩容规则)不允许重复。

          负载指标触发条件

          按负载伸缩规则进入触发状态时需满足的条件。您需要选择一个或多个系统定义的负载指标,选择多个系统定义的负载指标时,单击添加指标继续选择即可。该部分参数包含以下内容:

          • 负载指标:系统支持的负载指标名称。E-MapReduce弹性伸缩指标与YARN负载指标的对应关系,请参见E-MapReduce弹性伸缩指标与YARN服务的对应关系

            说明

            集群类型不同,系统支持的负载指标也不同,具体请您以控制台实际页面显示为准。

          • 统计办法:即判定负载指标值超出阈值范围的规则。选定的负载指标在一个统计周期内,按照选定的聚合维度(平均值、最大值和最小值),达到阈值为一次触发。

          多指标关系

          支持当所有指标都符合条件时触发任意一个指标符合条件时触发两种报警规则的选择方式。

          统计周期

          指标统计时长,弹性伸缩会根据统计周期收集、汇总和比较数据,粒度越小越易触发规则,请根据业务需要选择合理的统计周期。

          重复几次后扩容

          根据统计办法,负载指标值超出阈值后,弹性伸缩会记录次数,满足重复次数后才会触发相应的伸缩规则。

          单次扩容数

          负载规则被触发时,节点组每次触发伸缩活动增加的节点数量。

          尽力交付

          开启以后会按照最大成功数量交付。按负载伸缩受指标触发影响,是否开启可根据业务选择。

          冷却时间

          每次弹性伸缩动作开始,到可以再次进行弹性伸缩的时间间隔。在冷却时间内,即使满足弹性伸缩条件也不会发生弹性伸缩动作。即忽略本次在冷却时间内触发的弹性伸缩动作,直到下一次满足伸缩条件且不在冷却时间内再执行。

          当节点组完成伸缩活动并达到预期状态时,冷却时间可使后续触发伸缩活动的负载指标处于稳定状态。

          生效时间约束

          可选参数,用于控制按负载伸缩规则的生效时间范围。默认为全天24小时,设置后仅在设置的时间范围内触发伸缩活动。

    3. 配置完后,单击保存并应用

      当条件满足时会触发节点组的弹性伸缩活动。

方式二:创建集群时创建自定义伸缩规则

  1. 登录EMR on ECS

  2. 在顶部菜单栏处,根据实际情况选择地域和资源组

  3. 单击创建集群,参数详情请参见创建集群

    说明

    您必须在集群下添加按量付费TASK节点组,才可以配置相应的规则。

  4. 配置集群伸缩

    1. 选择自定义弹性伸缩规则,单击目标节点组操作列的编辑

    2. 配置弹性伸缩面板,配置相关参数,单击确定。参数详情请参见配置伸缩规则

    3. 配置完后,单击保存并应用

  5. 确认订单,创建集群。

    创建集群后,当规则满足时,会触发节点组的伸缩活动。

方式三:使用SDK创建自定义伸缩规则

在创建集群或节点组时,您可以为节点组配置自定义的伸缩规则,以实现节点的自动创建和管理。详情请参见CreateCluster - 创建集群CreateNodeGroup - 创建节点组。您也可以为已有节点组配置自定义伸缩规则,详情请参见PutAutoScalingPolicy - 创建自定义弹性伸缩策略

以下以Java代码为例,配置了一个按负载的弹性伸缩规则。

说明

初始化凭据客户端时,建议使用更安全的STS方式。更多鉴权访问方式,请参见管理访问凭据

// This file is auto-generated, don't edit it. Thanks.
package com.aliyun.sample;

import com.aliyun.tea.*;

public class Sample {

    /**
     * <b>description</b> :
     * <p>使用AK&amp;SK初始化账号Client</p>
     * @return Client
     * 
     * @throws Exception
     */
    public static com.aliyun.emr20210320.Client createClient() throws Exception {
        // 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。
        // 建议使用更安全的 STS 方式
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
                .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
                // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
                .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
        // Endpoint 请参考 https://api.aliyun.com/product/Emr
        config.endpoint = "emr.eu-central-1.aliyuncs.com";
        return new com.aliyun.emr20210320.Client(config);
    }

    public static void main(String[] args_) throws Exception {
        java.util.List<String> args = java.util.Arrays.asList(args_);
        com.aliyun.emr20210320.Client client = Sample.createClient();
        com.aliyun.emr20210320.models.ScalingConstraints scalingConstraints = new com.aliyun.emr20210320.models.ScalingConstraints()
                .setMaxCapacity(10)
                .setMinCapacity(0);
        com.aliyun.emr20210320.models.TriggerCondition scalingRule0MetricsTriggerTriggerCondition0 = new com.aliyun.emr20210320.models.TriggerCondition()
                .setMetricName("yarn_resourcemanager_queue_AvailableVCoresPercentage")
                .setStatistics("AVG")
                .setComparisonOperator("LE")
                .setThreshold(15D);
        com.aliyun.emr20210320.models.TriggerCondition scalingRule0MetricsTriggerTriggerCondition1 = new com.aliyun.emr20210320.models.TriggerCondition()
                .setMetricName("yarn_resourcemanager_queue_AvailableMBPercentage")
                .setStatistics("AVG")
                .setComparisonOperator("LE")
                .setThreshold(15D);
        com.aliyun.emr20210320.models.MetricsTrigger scalingRule0MetricsTrigger = new com.aliyun.emr20210320.models.MetricsTrigger()
                .setTimeWindow(300)
                .setEvaluationCount(1)
                .setCoolDownInterval(300)
                .setConditionLogicOperator("Or")
                .setConditions(java.util.Arrays.asList(
                    scalingRule0MetricsTriggerTriggerCondition0,
                    scalingRule0MetricsTriggerTriggerCondition1
                ));
        com.aliyun.emr20210320.models.ScalingRule scalingRule0 = new com.aliyun.emr20210320.models.ScalingRule()
                .setRuleName("default")
                .setTriggerType("METRICS_TRIGGER")
                .setActivityType("SCALE_OUT")
                .setAdjustmentValue(1)
                .setMetricsTrigger(scalingRule0MetricsTrigger);
        com.aliyun.emr20210320.models.PutAutoScalingPolicyRequest putAutoScalingPolicyRequest = new com.aliyun.emr20210320.models.PutAutoScalingPolicyRequest()
                .setRegionId("cn-hangzhou")
                .setClusterId("c-xxxx")
                .setNodeGroupId("ng-xxx")
                .setScalingRules(java.util.Arrays.asList(
                    scalingRule0
                ))
                .setConstraints(scalingConstraints);
        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
        try {
            // 复制代码运行请自行打印 API 的返回值
            client.putAutoScalingPolicyWithOptions(putAutoScalingPolicyRequest, runtime);
        } catch (TeaException error) {
            // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
            // 错误 message
            System.out.println(error.getMessage());
            // 诊断地址
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        } catch (Exception exception) {
            TeaException error = new TeaException(exception.getMessage(), exception);
            // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
            // 错误 message
            System.out.println(error.getMessage());
            // 诊断地址
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        }        
    }
}

E-MapReduce弹性伸缩指标与YARN服务的对应关系

E-MapReduce弹性伸缩指标

所属服务

说明

yarn_resourcemanager_queue_AvailableVCores

YARN

root队列可供分配的虚拟核数。

yarn_resourcemanager_queue_PendingVCores

YARN

root队列待分配的虚拟核数。

yarn_resourcemanager_queue_AllocatedVCores

YARN

root队列已分配的虚拟核数。

yarn_resourcemanager_queue_ReservedVCores

YARN

root队列预留的虚拟核数。

yarn_resourcemanager_queue_AvailableMB

YARN

root队列可供分配的内存量。

yarn_resourcemanager_queue_PendingMB

YARN

root队列待分配的内存量。

yarn_resourcemanager_queue_AllocatedMB

YARN

root队列已分配的内存量。

yarn_resourcemanager_queue_ReservedMB

YARN

root队列预留的内存量。

yarn_resourcemanager_queue_AppsRunning

YARN

root队列运行中的任务数。

yarn_resourcemanager_queue_AppsPending

YARN

root队列挂起的任务数。

yarn_resourcemanager_queue_AppsKilled

YARN

root队列终止的任务数。

yarn_resourcemanager_queue_AppsFailed

YARN

root队列失败的任务数。

yarn_resourcemanager_queue_AppsCompleted

YARN

root队列完成的任务数。

yarn_resourcemanager_queue_AppsSubmitted

YARN

root队列提交的任务数。

yarn_resourcemanager_queue_AllocatedContainers

YARN

root队列已分配的容器数。

yarn_resourcemanager_queue_PendingContainers

YARN

root队列待分配的容器数。

yarn_resourcemanager_queue_ReservedContainers

YARN

root队列预留的容器数。

yarn_resourcemanager_queue_AvailableMBPercentage

YARN

root队列可用内存资源所占百分比。(MemoryAvailablePrecentage= AvailableMemory/Total Memory)

说明

EMR-3.43.0及之后版本、EMR-5.9.0及之后版本支持该指标。

yarn_resourcemanager_queue_PendingContainersRatio

YARN

root队列待分配的容器数与已分配的容器数的比率。 (ContainerPendingRatio = PendingContainers/AllocatedContainers)。

说明

EMR-3.43.0及之后版本、EMR-5.9.0及之后版本支持该指标。

yarn_resourcemanager_queue_AvailableVCoresPercentage

YARN

root队列可用CPU核数资源所占百分比。AvailableVCoresPercentage = AvailableVCores / (ReservedVCores + AvailableVCores + AllocatedVCores) * 100

说明

EMR-3.43.0及之后版本、EMR-5.9.0及之后版本支持该指标。

yarn_cluster_numContainersByPartition

YARN

指定分区的容器数量,参数partition_name为分区名称。

说明

EMR-3.44.0及之后版本、EMR-5.10.0及之后版本支持该指标。

yarn_cluster_usedMemoryMBByPartition

YARN

指定分区的内存使用量,参数partition_name为分区名称,空字符串为默认分区。

说明

EMR-3.44.0及之后版本、EMR-5.10.0及之后版本支持该指标。

yarn_cluster_availMemoryMBByPartition

YARN

指定分区的内存可用量,参数partition_name为分区名称,空字符串为默认分区。

说明

EMR-3.44.0及之后版本、EMR-5.10.0及之后版本支持该指标。

yarn_cluster_usedVirtualCoresByPartition

YARN

指定分区的CPU核数使用量,参数partition_name为分区名称,空字符串为默认分区。

说明

EMR-3.44.0及之后版本、EMR-5.10.0及之后版本支持该指标。

yarn_cluster_availableVirtualCoresByPartition

YARN

指定分区的CPU核数可用量,参数partition_name为分区名称,空字符串为默认分区。

说明

EMR-3.44.0及之后版本、EMR-5.10.0及之后版本支持该指标。

常见问题

为什么EMR集群会弹性扩容失败?如何提升扩容成功率?

原因分析:

  1. ECS资源库存不足:当尝试为EMR集群进行弹性扩容时,指定的ECS实例规格节点数超过了当前可用区下该规格的ECS实例库存数,扩容操作将会失败。这是因为底层ECS资源是动态变化的,有时可能因为高需求而暂时短缺。

  2. 单个实例规格限制:如果您的弹性伸缩配置仅指定了单一类型的ECS实例规格,并且该类型恰好处于紧缺状态,则可能导致整个扩容过程受阻。

解决方案:

  • 建议开启尽力交付:在设置弹性伸缩规则时,开启“尽力交付”开关。这样即使遇到部分资源不可用的情况,系统也会尽可能地按照最大成功数量交付,而不是完全放弃此次扩容请求。

  • 建议配置多种实例规格:为了提高成功概率,在配置Task节点组时推荐配置多种不同的ECS实例规格,详情请参见新增节点组。这样,扩容的时候会从第一个规格尝试购买,在某一种规格无法获取到足够数量的情况下,系统可以自动尝试购买列表中的下一个规格,直到找到合适的为止或直至所有选项都被尝试过。

通过上述措施,您可以有效提升EMR集群弹性扩容的成功率。