亚马逊AWS官方博客

Amazon EC2自动化弹性纵向扩缩容方案

概述

现代化应用在云端通常都是采用横向扩缩容的方式来应对流量变化,例如在 Amazon EC2 中使用自动伸缩组(Auto Scaling Groups)。然而在一些传统行业,例如传统金融领域的证券行业,因为行业属性导致的 IT 系统的高稳定性要求等,弹性横向扩缩容方式的应用现代化改造进展是谨慎且缓慢的(例如,为了确保公平性,一些交易撮合引擎通常会在单台机器上运行),现状是大部分应用不自持弹性横向扩缩容,无法充分享受云计算的弹性优势。只有当长时间计算资源的使用率较低时,才会引发行政命令式的、手动地纵向扩缩容,即增减单台 EC2 的 CPU 或内存。为了帮助这类行业,能在兼容其应用现代化的发展程度前提下更好地利用云服务的弹性和自动化能力,探索自动化的纵向扩缩容方案非常有必要。

本篇博客将详细介绍如何对 Amazon EC2 实例实现自动化弹性纵向扩缩容,让这些行业的应用能根据实际需求动态调整单台 EC2 实例的计算资源,享受云端资源的灵活性和经济性,从而优化资源利用率和成本效益。

业务流程

在高稳定要求的金融行业,人工审批流程是关键生产环境变更中不可或缺的一环。本方案中,在 EC2 实例进行自动化弹性纵向扩缩容的时候,融入了人工审批流程的设计。详见下面的泳道图:

监控与判断扩缩容需求

该解决方案利用 Amazon CloudWatch 指标,获取 EC2 实例的 CPU 利用率和内存使用情况,当这些指标超过预设阈值时,系统即判断需要进行纵向扩缩容调整。并且根据事先设置好的规则推荐更具性价比的实例类型。

人工审批与调度执行

出于对生产环境的谨慎管理,扩缩容操作需要经过人工审批。一旦检测到需求,系统会自动向应用团队发送电子邮件通知,邮件中包含审批链接,审批人员可以在链接中指定期望的扩缩容执行时间。系统会根据该时间安排定时任务,在到期时自动执行扩缩容操作,避免影响核心业务时段。

平滑扩缩容与配置管理

在实际执行扩缩容前,系统会提前通知应用团队进行准备。扩缩容过程中,会通过 AWS Systems Manager 预先定义的自动化功能平滑地修改 EC2 实例类型, 确保新实例可以正常运行应用程序。

扩缩容完成后,系统会再次通知应用团队,他们可以验证应用状态,做进一步调整。这种模式最大限度减少了扩缩容对业务的影响。

通过将自动化与人工审批相结合,该解决方案在提高资源利用效率的同时,也为管理人员保留了对关键资源的掌控权。

解决方案架构

本 EC2 实例自动化弹性纵向扩缩容方案的架构如下图所示:

该架构包括以下几个主要组件和步骤:

  1. Amazon EventBridge:按照需求定时调用 AWS Lambda function 来查询 CPU 利用率、内存使用情况判断是否需要扩缩容
  2. AWS Lambda:调用 CloudWatch API 获取 EC2 实例的指标,如 CPU 利用率、内存使用情况等。当指标超过预设阈值时,会给出推荐实例类型,并SNS来通知用户。
  3. Amazon SNS:发送邮件给用户,其中包括设置扩缩容任务时间的链接。
  4. Amazon API Gateway 和 AWS Lambda:API Gateway 响应客户对链接的点击,并根据用户的输入时间调用 AWS Lambda function 来创建扩缩容的定时任务。
  5. Amazon EventBridge Scheduler和AWS Lambda:到了扩缩容时间,Scheduler 调用 AWS Lambda function 来执行纵向扩缩容任务,并再次发出 SNS 来通知用户。
  6. AWS Systems Manager:最终执行自动化来修改 EC2 实例,确保实例类型变更能顺利进行。

下面对几个关键组件及作用进详细的解释。

Amazon CloudWatch

对于 AWS EC2 实例,CloudWatch 是一个非常好的监控工具。它可以获取每台 EC2 实例的 CPU 利用率,在实例上安装了 CloudWatch Agent 后,还可以获取到实例的内存和硬盘利用率等指标。CloudWatch 还可以支持通过简单的指标与阈值的比较逻辑触发告警通知,并可触发联动操作,如调用 Lambda、触发 auto scaling 等,来优化工作负载。不过对于比较复杂的指标与阈值判断逻辑,还需采用 sdk 方式来调用 CloudWatch 接口进行灵活地实现。

本方案根据 CPU 和内存使用率及阀值来判断扩缩容的逻辑如下:

扩缩选项 指标名 处理逻辑
缩容 cpuutilization 7 天内的每个小时的平均值都小于预先设置的 cpu 缩容阀值,则判定 cpu 需要缩容
mem_used_percent 7 天内的每个小时的平均值都小于预先设置的 mem 缩容阀值,则判定内存需要缩容
扩容 cpuutilization 7 天内的有 5 个小时的平均值都大于等于预先设置的 cpu 扩容阀值,则判定 cpu 需要扩容
mem_used_percent 7 天内的有 5 个小时的平均值都大于等于预先设置的 mem 扩容阀值,则判定内存需要扩容

Amazon EC2 实例的选择

对于 AWS EC2 实例,需要根据不同的使用场景选择合适的实例系列及规格。常用的实例系列包括 M 系列、C 系列和R 系列。

  • M 系列实例的 vCPU 和内存比例通常为 1 个 vCPU 对应 4GB 内存,适合于均衡的计算和内存需求。
  • C 系列实例的 vCPU 和内存比例通常为 1 个 vCPU 对应 2GB 内存,更加侧重计算能力,适合于计算密集型工作负载。
  • R 系列实例的 vCPU 和内存比例通常为 1 个 vCPU 对应 8GB 内存,内存资源更加丰富,适合于内存密集型应用程序。

更多详情请参考:https://aws.amazon.com/ec2/instance-types/

为达到资源利用的最优化,我们会通过监控 EC2 实例的 CPU 利用率和内存利用率,根据实际运行需求调整实例的系列及规格。例如,如果发现 CPU 利用率较高但内存利用率正常,我们可以考虑增加 vCPU 的数量,而保持内存不变;反之,如果内存利用率较高但 CPU 利用率正常,我们则可以增加内存容量。

本方案在调整实例的系列和规格时,会尽量选择与当前实例规格最接近的新规格,以避免给应用程序带来较大的变动和影响。这种渐进式的调整方式可以使应用程序更加平稳地过渡到新的资源配置。

具体调整逻辑参考如下:

CPU/内存扩缩容 内存缩容 内存不变 内存扩容
CPU 缩容 同系列缩一档 根据当前机系列不同处理:
R:保持原状
M:转 R 系降一档
C:转 M 系降一档
根据当前机系列不同处理:
R:原系列升一档
M:转 R 系同档
C:转 M 系同档
CPU 不变 根据当前机系列不同处理
R:转 M 系同档
M:转 C 系同档
C:保持原状
保持原状 根据当前机系列不同处理
R:原系列升一档
M:转 R 系同档
C:转 M 系同档
CPU 扩容 根据当前机系列不同处理
R:转 M 系升一档
M:转 C 系升一档
C:同系升一档
根据当前机系列不同处理
R:转 M 系升一档
M:转 C 系升一档
C:同系升一档
同系列扩一档

AWS Lambda

AWS Lambda 是 AWS 云原生的无服务器函数式计算服务,可以运行您的代码以响应事件并自动管理计算资源。通过 AWS Lambda,无需预置或管理服务器即可运行代码。它支持多种开发语言运行时,在 Lambda 函数中可编写代码调用 AWS 各种服务来完成各种出色的任务。

本方案中,用 Python 语言及 Amazon boto3 库,主要实现了如下 3 个 Lambda 函数:

  1. 用于被定时重复执行 Scheduler 调用的 、获取 EC2 的用量指标并进行阀值逻辑处理及推荐新 EC2 实例类型的 Lambda 函数(上节所述逻辑的实现)。
  2. 用于创建按时单次执行扩缩容的 Scheduler 的 Lambda 函数。
  3. 用于调用 SSM automation 完成 EC2 实例类型变更的 Lambda 函数。

部分代码实例如下:

def lambda_handler(event, context):
    cloudwatch = boto3.client('cloudwatch',region_name='ap-east-1')
    #get parameter
    instance_id=event['instance_id']
    cpu_threshold_upsize=float(event['cpu_threshold_upsize'])*100
    mem_threshold_upsize=float(event['mem_threshold_upsize'])*100
    cpu_threshold_downsize=float(event['cpu_threshold_downsize'])*100
    mem_threshold_downsize=float(event['cpu_threshold_downsize'])*100
  
    #check metric and decide upsize or downsize or keep as is
    period = 3600 # 1 hours
    statistic = 'Average'  # e.g., 'Average', 'Sum', 'Minimum', 'Maximum'
    start_time = datetime.now(timezone.utc)- timedelta(days=7)
    end_time = datetime.now(timezone.utc)
    #check cpu
    metric_name = 'CPUUtilization'
    namespace = 'AWS/EC2'
    print(f"begin call cloudwatch for ec2 cpu metric data")
    cpu_down=False
    cpu_up=False
    bypass_times=0
    bypass_times_threshold=7
    try:
      cpu_response = cloudwatch.get_metric_data(
        MetricDataQueries=[
            {
                'Id': "query_cpu",
                'MetricStat': {
                    'Metric': {
                        'Namespace': namespace,
                        'MetricName': metric_name,
                        'Dimensions': [
                        {
                            'Name': 'InstanceId',
                            'Value': instance_id
                        }
                    ]
                    },
                    'Period': period,
                    'Stat': statistic
                },
                'ReturnData': True
            }
        ],
        StartTime=start_time,
        EndTime=end_time
     )
      cpu_metric_data_points = cpu_response['MetricDataResults'][0]['Values']
      print(f"begin call cloudwatch for ec2 cpu metric data ok,no exception")
      print(f"cpu metric data name={metric_name}, value={cpu_metric_data_points}")
      # downsize check
      cpu_down = all(float(value) < cpu_threshold_downsize for value in cpu_metric_data_points)
         #upsize check
      bypass_times=0
      bypass_times_threshold=7
      for  value in cpu_metric_data_points:
        if float(value) > cpu_threshold_upsize :
            bypass_times+=1
      cpu_up=bypass_times>=bypass_times_threshold
…

完整代码可参考【解决方案代码及部署】部分的说明。

Amazon API Gateway

Amazon API Gateway 是一种完全托管的服务,可以帮助开发人员轻松创建、发布、维护、监控和保护任意规模的 API。

本方案中 ,Amazon API Gateway 用于以 Rest 风格的 URL 形式,把创建 Scheduler 的能力暴露给客户,为整个方案提供手动干预变更窗口的能力。

其效果如下图所示:

AWS Systems Manager

AWS Systems Manager 是一项综合的云管理服务,它提供了一系列功能来帮助管理和自动化 AWS 资源的操作。在 EC2 实例扩缩容的过程中,我们使用了 Systems Manager 的自动化功能 AWS-ResizeInstance。

AWS-ResizeInstance 是一个内置的工具,它可以自动检查 EC2 实例是否已经达到目标实例类型,如果不是,它会执行以下步骤:

  1. 停止当前 EC2 实例
  2. 修改实例类型为目标类型
  3. 启动已修改的 EC2 实例

通过使用这个自动化工具,我们可以避免手动执行上述步骤,从而减少人为操作错误的风险,同时也提高了效率。

解决方案代码及部署

整体方案代码。整体方案已经用 Python +CDK 进行了 IaC 化,如果您对这个解决方案有兴趣,可以从下面的 repository 下载 sample codes,部署到您的测试环境进行体验。

https://github.com/aws-samples/cloud-instance-vertical-autoscaler

解决方案的部署。请参考 sample codes 的 README.md 文件的 Getting Started 部分:

该 sample codes 仅供您参考,应用到具体场景中时,可根据您的实际需求进行修改。

总结

通过利用 CloudWatch、EventBridge、Lambda、API Gateway 、SNS和 Systems Manager 等 AWS 云服务,我们构建了一个自动化的解决方案,实现了对 EC2 实例的自动化弹性纵向扩缩容。

该解决方案可以持续监控 EC2 实例的资源利用情况,并支持根据预设阈值的复杂判断逻辑,自动地来判断是否需要扩缩容,还能给出推荐的新 EC2 实例类型。一旦检测到扩缩容需求,系统会发送通知给应用团队进行人工审批。经过审批后,系统会安排在指定时间执行扩缩容操作,并在执行前后分别通知应用团队,让他们有机会进行应用检查和验证。通过这种自动化和人工审批相结合的模式,不仅提高了资源利用效率,也为管理人员保留了对关键资源的掌控权。

对于现代化改造谨慎的行业的应用,该解决方案让它们也能提前享受到云端资源灵活调配的优势,真正发挥云计算的弹性和经济性。

本篇作者

崔保亮

亚马逊云科技金融行业解决方案架构师

Jacky Wu

亚马逊云科技金融行业解决方案架构师

Louis Lo

亚马逊云科技技术客户经理

胡仲海

华泰证券架构委员会架构师

Ricky Chu

华泰金控(香港)资讯科技部基础设施项目经理