

# Amazon ECS 自动扩缩和容量管理最佳实践
<a name="capacity-availability"></a>

您可以在 Amazon ECS 上运行各种规模的容器化应用程序工作负载。这包括最小的测试环境和在全球范围内运行的大型生产环境。

与所有 AWS 服务一样，使用 Amazon ECS 时，您只需按实际用量付费。对应用程序进行合理的架构设计时，便能够仅在需要时使用所需资源，以此节约成本。

以下建议向您展示如何运行 Amazon ECS 工作负载以实现服务级别目标，同时又能采用经济高效的方式运营。

**Topics**
+ [确定 Amazon ECS 的任务大小](capacity-tasksize-best-practice.md)
+ [优化 Amazon ECS 服务自动扩缩](capacity-autoscaling-best-practice.md)
+ [Amazon ECS 容量和可用性](capacity-availability-best-practice.md)
+ [Amazon ECS 集群容量](capacity-cluster-best-practice.md)
+ [为 Amazon ECS 选择 Fargate 任务大小](fargate-task-size-best-practice.md)
+ [在 Amazon EC2 上使用容量提供程序加快 Amazon ECS 集群的容量预置](capacity-cluster-speed-up-ec2-best-practice.md)

# 确定 Amazon ECS 的任务大小
<a name="capacity-tasksize-best-practice"></a>

在 Amazon ECS 上部署容器时，要做的最重要的选择之一就是容器和任务大小。容器和任务大小对于扩缩和容量规划都至关重要。

Amazon ECS 使用两个资源指标来测量容量：CPU 和内存。Amazon ECS 以整个 vCPU 的 1/1024 为单位来测量 CPU（其中 1024 个单位等于一整个 vCPU）。Amazon ECS 以兆字节为单位测量内存。

在任务定义中，您可以声明资源预留和限制。

当您声明预留时，您就是在声明任务所需的最低资源量。您的任务至少会收到所请求的资源量。您的应用程序可能能够使用比您声明的预留更多的 CPU 或内存。但是，这受制于您所声明的任何限制。

使用超过预留量被称为突增。爆增意味着应用程序使用的资源多于预留的资源，但仍保持在您声明的限制范围内。Amazon ECS 保证预留。例如，如果您使用 Amazon EC2 实例来提供容量，则 Amazon ECS 不会将任务放置在无法完成预留的实例上。

限制是指您的容器或任务可以使用的最大 CPU 单位量或内存量。如果您的容器尝试使用超过此限制的 CPU，Amazon ECS 会对其进行节流。如果您的容器尝试使用超过此限制的内存，Amazon ECS 会停止容器。

选择这些值可能会具有挑战性。最适合您的应用程序的值在很大程度上取决于应用程序的资源需求。

对应用程序进行负载测试是成功规划资源需求的关键。负载测试可帮助您更好地了解应用程序的需求。

## 无状态应用程序
<a name="capacity-tasksize-stateless"></a>

对于水平扩缩的无状态应用程序，例如负载均衡器后面的应用程序，建议您首先确定应用程序在提供请求时消耗的内存量。

为此，您可以使用传统工具，例如 `ps` 或 `top`。您还可以使用 CloudWatch Container Insights 等监控解决方案。

在确定 CPU 预留时，请考虑如何扩缩应用程序以满足您的业务需求。

您可以使用较小的 CPU 预留（例如 256 个 CPU 单元（或 1/4 vCPU），以细粒度的方式进行横向扩展，从而最大限度地降低成本。但是，它们的扩缩速度可能不够快，无法满足需求的显著激增。

您可以使用更大的 CPU 预留来更快地横向缩减和横向扩展。这有助于您更快地匹配需求激增。但是，预留的 CPU 越大，成本就越高。

## 其他客户端应用程序
<a name="capacity-tasksize-other"></a>

对于无法横向扩缩的应用程序（例如单例 Worker 或数据库服务器），可用容量和成本是您最重要的考虑因素。

根据负载测试所示的提供流量和满足服务级别目标所需的配置，选择内存量和 CPU 数量。Amazon ECS 可确保将应用程序放置在具有足够容量的主机上。

# 优化 Amazon ECS 服务自动扩缩
<a name="capacity-autoscaling-best-practice"></a>

Amazon ECS 服务是一个托管任务集合。每项服务都有关联的任务定义、所需的任务计数和可选的放置策略。

Amazon ECS 服务自动扩缩通过 Application Auto Scaling 服务实现。Application Auto Scaling 使用 CloudWatch 指标作为扩展指标的来源。它还使用 CloudWatch 警报来设置何时横向缩减或横向扩展服务的阈值。

您可以提供扩缩阈值。您可以设置指标目标，这称为*目标跟踪扩缩*。您还可以指定阈值，这称为*分步扩缩*。

配置 Application Auto Scaling 后，它会持续计算服务的相应所需任务数。它还会在所需的任务计数发生变化时通过横向扩展或横向缩减来通知 Amazon ECS。

要有效地使用服务自动扩缩，必须选择适当的扩缩指标。我们将在以下各节中讨论如何选择指标。

## 描述应用程序的特性
<a name="capacity-autoscaling-app"></a>

要正确扩缩应用程序，您需要知道应在何种条件下横向缩减应用程序，以及何时应横向扩展应用程序。

本质上，如果预计需求将超过容量，则应横向扩展应用程序。相反，当资源超过需求时，可以横向缩减应用程序以节省成本。

### 确定利用率指标
<a name="capacity-autoscaling-app-utilizationmetric"></a>

要有效地进行扩缩，必须确定一个表明利用率或饱和度的指标。此指标必须显示以下属性才能用于扩缩。
+ 该指标必须与需求相关联。当资源保持稳定，但需求发生变化时，指标值也必须发生变化。当需求增加或减少时，该指标也应增加或减少。
+ 指标值必须与容量成比例地横向缩减。当需求保持不变时，增加更多资源必须导致指标值按比例变化。因此，将任务数增加一倍应该会使该指标减少 50%。

标识利用率指标的最佳方法是在预生产环境（例如暂存环境）中进行负载测试。商业和开源负载测试解决方案广泛可用。这些解决方案通常可以生成合成负载，或模拟真实的用户流量。

要开始负载测试过程，应先为应用程序的利用率指标构建控制面板。这些指标包括 CPU 利用率、内存利用率、I/O 操作、I/O 队列深度和网络吞吐量。您可以使用 CloudWatch Container Insights 等服务收集这些指标。您还可以将 Amazon Managed Service for Prometheus 与 Amazon Managed Grafana 配合使用，以收集这些指标。在此过程中，请确保收集应用程序响应时间或工作完成率指标并绘制其图形。

进行负载测试时，请从小的请求或作业插入率开始。将此速率保持稳定几分钟，让您的应用程序进行预热。然后，慢慢提高速率并使其保持稳定几分钟。重复此周期，每次都提高速率，直到应用程序的响应或完成时间太慢而无法达到服务级目标（SLO）。

进行负载测试时，请检查每个利用率指标。随负载增加而增加的指标最适合作为最佳利用率指标。

接下来，识别已达到饱和度的资源。同时，还要检查利用率指标，看看哪个指标首先在高水平上趋于平缓。或者，检查哪个指标达到峰值，然后首先使应用程序崩溃。例如，如果随着负载增加，CPU 利用率从 0% 增加到 70-80%，然后在增加更多负载后仍保持在该水平，则可以肯定地说 CPU 已饱和。根据 CPU 架构的不同，它可能永远不会达到 100%。例如，假设内存利用率随负载的增加而增加，然后您的应用程序在达到任务或 Amazon EC2 实例内存限制时突然崩溃。这种情况下，很可能是内存已被完全消耗。您的应用程序可能会消耗多种资源。因此，请选择表示首先耗尽的资源的指标。

最后，在任务数或 Amazon EC2 实例数增加一倍后，再次尝试负载测试。假设关键指标的增加或减少速度是以前的一半。如果是这种情况，则指标与容量成正比。这是自动扩缩的一个很好的利用率指标。

现在考虑一下这个假设场景。假设您对应用程序进行负载测试，并发现每秒 100 个请求时 CPU 利用率最终达到 80%。当增加更多负载时，CPU 利用率不会再提高。但是，它确实会使您的应用程序的响应速度变慢。然后，您再次运行负载测试，将任务数增加一倍，但将速率保持在之前的峰值水平。如果您发现平均 CPU 利用率降至 40% 左右，则平均 CPU 利用率是扩缩指标的理想选择。另一方面，如果增加任务数后 CPU 利用率保持在 80%，则平均 CPU 利用率不是一个很好的扩缩指标。这种情况下，需要进行更多的研究才能找到合适的指标。

### 常见的应用程序模型和扩缩属性
<a name="capacity-autoscaling-app-common"></a>

各种软件都可以在 AWS 上运行。许多工作负载是自主开发的，而另一些工作负载则基于常见的开源软件。无论它们来自哪里，我们都观察到了一些常见的服务设计模式。如何有效扩缩很大程度上取决于模式。

#### 高效的 CPU 绑定服务器
<a name="capacity-autoscaling-app-common-cpu"></a>

除了 CPU 和网络吞吐量之外，高效的 CPU 绑定服务器几乎不利用任何资源。每个请求都可以由应用程序单独处理。请求不依赖于数据库等其他服务。应用程序可以处理成千上万个并发请求，并且可以高效地利用多个 CPU 来执行此操作。每个请求或由内存开销较低的专用线程提供服务，或者在为请求提供服务的每个 CPU 上运行一个异步事件循环。应用程序的每个副本都同样能够处理请求。可能在 CPU 之前耗尽的唯一资源是网络带宽。在 CPU 绑定服务中，即使在吞吐量峰值下，内存利用率也只是可用资源的一小部分。

可以将基于 CPU 的自动扩缩用于这种类型的应用程序。该应用程序在扩缩方面具有最大的灵活性。可以通过向其提供更大的 Amazon EC2 实例或 Fargate vCPU 来对其进行纵向扩缩。而且，还可以通过添加更多副本对其进行横向扩缩。添加更多副本或将实例大小增加一倍，可将平均 CPU 利用率（相对于容量）降低一半。

如果您为此应用程序使用 Amazon EC2 容量，则请考虑将其放置在计算优化型实例上，例如 `c5` 或 `c6g` 系列。

#### 高效的内存绑定服务器
<a name="capacity-autoscaling-app-common-memory"></a>

高效的内存绑定服务器为每个请求分配大量内存。在最大并发（但不一定是吞吐量）下，内存会在 CPU 资源耗尽之前耗尽。请求结束时，与请求关联的内存会被释放。只要有可用内存，就可以接受额外请求。

可以将基于内存的自动扩缩用于这种类型的应用程序。该应用程序在扩缩方面具有最大的灵活性。可以通过向其提供更大的 Amazon EC2 或 Fargate 内存资源来对其进行纵向扩缩。而且，还可以通过添加更多副本对其进行横向扩缩。添加更多副本或将实例大小增加一倍，可将平均内存利用率（相对于容量）降低一半。

如果您为此应用程序使用 Amazon EC2 容量，请考虑将其放置在内存优化型实例上，例如 `r5` 或 `r6g` 系列。

某些受内存限制的应用程序在某项请求结束时不会释放与该请求关联的内存，因此并发度的降低不会导致使用的内存减少。为此，不建议您使用基于内存的扩缩。

#### 基于工作线程的服务器
<a name="capacity-autoscaling-app-common-worker"></a>

基于工作线程的服务器一个接一个地处理每个工作线程的请求。工作线程可以是轻量级线程，例如 POSIX 线程。它们也可以是重量级线程，例如 UNIX 进程。无论它们是哪个线程，应用程序可以支持的最大并发度总是存在的。通常，并发限制根据可用的内存资源按比例设置。如果达到并发限制，应用程序会将其他请求放入积压队列中。如果积压队列溢出，应用程序会立即拒绝其他传入请求。符合这种模式的常见应用程序包括 Apache Web 服务器和 Gunicorn。

请求并发度通常是扩缩此应用程序的最佳指标。由于每个副本都有并发限制，因此务必在达到平均限制之前进行横向扩展。

获取请求并发指标的最佳方法是让您的应用程序将其报告给 CloudWatch。应用程序的每个副本都可以将并发请求数量作为自定义指标高频率发布。建议将频率设置为至少每分钟一次。收集多个报告后，您可以使用平均并发度作为扩缩指标。此指标通过将总并发度除以副本数计算得出。例如，如果总并发度为 1000，副本数为 10，则平均并发度为 100。

如果您的应用程序位于应用程序负载均衡器之后，则您也可以使用负载均衡器的 `ActiveConnectionCount` 指标作为扩缩指标中的一个因子。必须将 `ActiveConnectionCount` 指标除以副本数才能得出平均值。必须使用平均值进行扩缩，而不是使用原始计数值。

为了使该设计发挥最佳效果，在低请求速率下，响应延迟的标准差应该较小。建议在需求低迷时期，在短时间内答复大多数请求，并且没有多少请求需要的时间比平均响应时间长得多。平均响应时间应接近第 95 个百分位响应时间。否则，可能会导致发生队列溢出。这会导致错误。建议您在必要时提供其他副本，以缓解溢出风险。

#### 等待服务器
<a name="capacity-autoscaling-app-common-waiting"></a>

等待服务器会对每个请求进行一些处理，但它高度依赖于一个或多个下游服务运行。容器应用程序经常会大量使用下游服务，例如数据库和其他 API 服务。这些服务可能需要一些时间才能做出响应，尤其是在高容量或高并发场景中。这是因为这些应用程序往往使用很少的 CPU 资源，并利用可用内存方面的最大并发性。

等待服务既适用于内存绑定的服务器模式，也适用于基于工作线程的服务器模式，具体取决于应用程序的设计方式。如果应用程序的并发度仅受内存限制，则应使用平均内存利用率作为扩缩指标。如果应用程序的并发度基于工作线程限制，则应使用平均并发度作为扩缩指标。

#### 基于 Java 的服务器
<a name="capacity-autoscaling-app-common-java"></a>

如果您的基于 Java 的服务器受 CPU 约束，并且与 CPU 资源成比例地扩展，则它可能适合高效的 CPU 绑定服务器模式。如果是这种情况，则平均 CPU 利用率可能适合作为扩缩指标。但是，许多 Java 应用程序不受 CPU 限制，因此难以扩展。

为了获得最佳性能，建议您为 Java 虚拟机（JVM）堆分配尽可能多的内存。最新版本的 JVM（包括 Java 8 更新 191 或更高版本）会自动将堆大小设置得尽可能大，以容纳到容器中。这意味着，在 Java 中，内存利用率很少与应用程序利用率成正比。随着请求速率和并发度提高，内存利用率保持不变。因此，不建议根据内存利用率扩缩基于 Java 的服务器。相反，通常建议按 CPU 利用率扩缩。

某些情况下，基于 Java 的服务器在耗尽 CPU 之前会遇到堆耗尽的情况。如果您的应用程序在高并发时容易出现堆耗尽的情况，则平均连接数是最好的扩缩指标。如果您的应用程序在高吞吐量时容易出现堆耗尽的情况，则平均请求率是最好的扩缩指标。

#### 使用其他垃圾回收运行时的服务器
<a name="capacity-autoscaling-app-common-garbage"></a>

许多服务器应用程序都基于执行垃圾回收的运行时，例如 .NET 和 Ruby。这些服务器应用程序可能符合前面描述的模式之一。但是，与 Java 一样，不建议根据内存扩缩这些应用程序，因为它们观察到的平均内存利用率通常与吞吐量或并发度不相关。

对于这些应用程序，如果应用程序受 CPU 限制，建议您按 CPU 利用率扩展。否则，建议您根据负载测试结果按平均吞吐量或平均并发度扩展。

#### 作业处理器
<a name="capacity-autoscaling-app-common-job"></a>

许多工作负载都涉及异步作业处理。它们包括不实时接收请求，而是通过订阅工作队列来接收作业的应用程序。对于这些类型的应用程序，正确的扩缩指标几乎总是队列深度。队列增长表明待处理的工作超过了处理能力，而空队列则表示容量大于要做的工作。

诸如 Amazon SQS 和 Amazon Kinesis Data Streams 之类的 AWS 消息收发服务提供了可用于扩缩的 CloudWatch 指标。对于 Amazon SQS，`ApproximateNumberOfMessagesVisible` 是最好的指标。对于 Kinesis Data Streams，可以考虑使用 `MillisBehindLatest` Kinesis Client Library（KCL）发布的指标。在使用该指标进行扩缩之前，应在所有使用者之间求它的平均值。

# Amazon ECS 容量和可用性
<a name="capacity-availability-best-practice"></a>

应用程序可用性对于提供无错误体验和最大限度降低应用程序延迟至关重要。可用性取决于是否拥有可访问的资源并有足够的容量来满足需求。AWS 提供了几种管理可用性的机制。对于托管在 Amazon ECS 上的应用程序，这些机制包括自动扩缩和可用区（AZ）。自动扩缩根据您定义的指标管理任务或实例的数量，而可用区则允许您将应用程序托管在孤立但地理位置接近的位置。

与任务规模一样，容量和可用性也存在您必须考虑的某些权衡。理想情况下，容量将与需求完全一致。总是有足够的容量来提供请求和处理作业，以满足服务级别目标（SLO），包括低延迟和错误率。容量永远不会太高，导致成本过高；也永远不会太低，导致高延迟和错误率。

自动扩缩是一个潜在过程。首先，CloudWatch 必须接收实时指标。然后，CloudWatch 需要将它们汇总起来进行分析，这可能需要长达几分钟的时间，具体取决于指标的粒度。CloudWatch 将这些指标与警报阈值进行比较，以确定资源短缺或过剩情况。为防止不稳定，您应配置警报，要求在警报响起前必须超过设置的阈值几分钟。预调配新任务和终止不再需要的任务也需要时间。

由于系统存在这些潜在的延迟，应通过过度预置来保持一定的余量。过度预置有助于适应短期的需求爆增。这也有助于您的应用程序在不达到饱和的情况下服务额外的请求。作为一种良好的实践，您可以将扩缩目标设置在利用率的 60-80% 之间。这可以帮助您的应用程序更好地处理额外需求激增，同时仍在预调配更多容量。

建议您过度配置的另一个原因是，您可以快速响应可用区故障。AWS 建议从多个可用区提供生产工作负载。这是因为，如果一个可用区发生故障，则在剩余可用区中运行的任务仍然可以满足需求。如果应用程序在两个可用区中运行，则需要将正常任务数增加一倍。这样，您就可以在任何潜在故障期间提供即时容量。如果您的应用程序在三个可用区中运行，则建议您运行正常任务数的 1.5 倍。也就是说，对正常服务所需的每两个任务执行三个任务。

## 最大程度提高缩放速度
<a name="capacity-availability-speed"></a>

自动扩缩是一个被动的过程，需要时间才能生效。但是，有一些方法可以帮助最大限度地缩短横向扩展所需的时间。

**最小化映像大小。**较大的映像需要更长的时间才能从映像存储库中下载和解压缩。因此，缩小映像大小可以减少容器启动所需的时间。要缩小映像大小，您可以遵循以下具体建议：
+ 如果您可以构建静态二进制文件或使用 Golang，则请 `FROM` 从头开始构建映像，并在生成的映像中仅包含您的二进制应用程序。
+ 使用来自上游 Distro 供应商（例如 Amazon Linux 或 Ubuntu）的最小化基础映像。
+ 请勿在最终映像中包含任何生成构件。使用多阶段生成可以帮助解决这个问题。
+ 尽可能压缩 `RUN` 阶段。每个 `RUN` 阶段都会创建一个新的映像层，从而发起另一轮下载层的循环。具有由 `&&` 联接的多个命令的单个 `RUN` 阶段的层数少于具有多个 `RUN` 阶段的命令。
+ 如果您想在最终映像中包含机器学习推理数据等数据，则请仅包含启动和开始提供流量所需的数据。如果您在不影响服务的情况下按需从 Amazon S3 或其他存储中提取数据，则请改为将数据存储在这些位置。

**保持映像相互靠近。**网络延迟越高，下载映像所需的时间越长。将您的映像托管在与您的工作负载所在 AWS 区域相同的存储库中。Amazon ECR 是一个高性能映像存储库，在 Amazon ECS 所在的每个区域都可用。避免遍历互联网或使用 VPN 链接下载容器映像。将您的映像托管在同一区域可以提高整体可靠性。它缓解了不同区域出现网络连接问题和可用性问题的风险。或者，您还可以实施 Amazon ECR 跨区域复制来帮助解决这个问题。

**减小负载均衡器运行状况检查阈值。**负载均衡器在向您的应用程序发送流量之前执行运行状况检查。目标组的默认运行状况检查配置可能需要 90 秒或更长时间。在此期间，负载均衡器会检查运行状况，并接收请求。降低运行状况检查间隔和阈值计数可以使您的应用程序更快接受流量并减少其他任务的负载。

**请考虑冷启动性能。**有些应用程序使用运行时，例如 Java 执行即时（JIT）编译。编译过程至少可以在开始时显示应用程序的性能。一种解决方法是用不会造成冷启动性能损失的语言重新编写工作负载中延迟关键的部分。

**使用步进缩放，而不是目标跟踪缩放策略。**Amazon ECS 任务有数个 Application Auto Scaling 选项。目标跟踪是最易于使用的模式。有了它，您所需要做的就是为指标设置一个目标值，例如 CPU 平均利用率。然后，自动定标器会自动管理实现该值所需的任务数量。使用分步扩展，您可以更快地对需求变化做出反应，因为您可以定义扩展指标的特定阈值，以及在超过阈值时要添加或删除的任务数量。并且，更重要的是，您可以通过最大限度地减少突破阈值警报的时间来对需求变化做出快速反应。有关更多信息，请参阅《Amazon Elastic Container Service 开发人员指南》**中的[服务自动扩缩](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-auto-scaling.html)。

如果您使用 Amazon EC2 实例提供集群容量，则请考虑以下建议：

**使用更大的 Amazon EC2 实例和更快的 Amazon EBS 卷。**您可以使用更大的 Amazon EC2 实例和更快的 Amazon EBS 卷来提高映像下载和准备速度。在给定的 Amazon EC2 实例系列中，网络和 Amazon EBS 最大吞吐量会随着实例大小的增加而增加（例如，从 `m5.xlarge` 到 `m5.2xlarge`）。此外，您也可以自定义 Amazon EBS 卷以提高其吞吐量和 IOPS。例如，如果您使用的是 `gp2` 卷，则请使用能提供更高基准吞吐量的更大的卷。如果您使用的是 `gp3` 卷，则请在创建卷时指定吞吐量和 IOPS。

**请对在 Amazon EC2 实例上运行的任务使用桥式网络模式。**在 Amazon EC2 上使用 `bridge` 网络模式的任务比使用 `awsvpc` 网络模式的任务启动得更快。使用 `awsvpc` 网络模式时，Amazon ECS 会在启动任务之前将弹性网络接口（ENI）附加到实例。这样会带来额外的延迟。不过，使用桥式网络需要进行几项权衡。这些任务没有自己的安全组，并且会对负载均衡产生一些影响。有关更多信息，请参阅《弹性负载均衡用户指南》**中的[负载均衡器目标组](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html)。

## 处理需求冲击
<a name="capacity-availability-shocks"></a>

一些应用程序会突然经受巨大的需求冲击。发生这种情况的原因有很多：新闻事件、大促销、媒体事件或其他一些可以使流量在很短的时间内迅速显著增加的病毒式传播事件。如果是意外发生的，则可能会导致需求迅速超过可用资源。

处理需求冲击的最佳方法是预测它们并做出相应的计划。由于自动扩缩可能需要时间，因此建议您在需求冲击开始之前横向扩展应用程序。为了获得最佳结果，建议制定一项业务计划，其中包括使用共享日历的团队之间的紧密协作。计划活动的团队应提前与负责应用程序的团队密切合作。这使得该团队有足够的时间来制定明确的安排计划。他们可以安排容量，以便在活动开始前进行横向扩展，在活动结束后进行横向缩减。有关更多信息，请参阅《Application Auto Scaling 用户指南》**中的[计划扩展](https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-scheduled-scaling.html)。

如果您有企业级支持计划，则请同时确保与您的技术客户经理（TAM）合作。您的 TAM 可以验证您的服务配额，并确保在活动开始之前提高所有必要的配额。这样，您将不会意外达到任何服务配额。他们还可以通过预热服务（如负载均衡器等）来帮助您，以确保您的活动顺利进行。

处理计划外的需求冲击是一个更为困难的问题。计划外的冲击，如果幅度足够大，则会迅速导致需求超出容量。它还可以超越自动扩缩的反应能力。应对计划外冲击的最佳方法是过度配置资源。您必须拥有足够的资源来随时处理最大的预期流量需求。

在预期会出现计划外的需求冲击时保持最大容量可能会付出高昂的代价。为了缓解成本影响，请找到预测大规模需求冲击即将来临的领先指标或事件。如果指标或事件可靠地提供了重要的提前通知，则在事件发生或指标超过您设置的特定阈值时，立即开始横向扩展流程。

如果您的应用程序容易出现突然的计划外需求冲击，则请考虑在应用程序中添加一种高性能模式，该模式会牺牲掉非关键功能，但为客户保留关键功能。例如，假设您的应用程序可以切换，从生成昂贵的自定义响应切换到提供静态响应页面。在这种情况下，您可以在不扩缩应用程序的情况下显著提高吞吐量。

最后，您可以考虑拆分单体服务，以更好地应对需求冲击。如果您的应用程序是一项运行成本高昂且扩展速度较慢的单体服务，则可以提取或重写性能关键部分并将其作为单独的服务运行。然后，这些新服务可以独立于不太关键的组件进行扩展。能够灵活地将性能关键型功能与应用程序的其他部分分开横向扩展，既可以减少增加容量所需的时间，又有助于节省成本。

# Amazon ECS 集群容量
<a name="capacity-cluster-best-practice"></a>

您可以通过多种方式为 Amazon ECS 集群提供容量。例如，您可以启动 Amazon EC2 实例，并在启动时使用 Amazon ECS 容器代理将实例注册到集群中。但是，这种方法可能具有挑战性，因为您需要自己管理扩缩。因此，建议您使用 Amazon ECS 容量提供程序。容量提供程序可为您管理资源扩缩。有三种容量提供程序：Amazon EC2、Fargate 和 Fargate Spot。有关 Fargate 容量提供程序的更多信息，请参阅 [Fargate 的 Amazon ECS 集群](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/fargate-capacity-providers.html)，有关 EC2 工作负载，请参阅 [EC2 工作负载的 Amazon ECS 集群](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/asg-capacity-providers.html)。

Fargate 和 Fargate Spot 容量提供程序会为您处理 Fargate 任务的生命周期。Fargate 提供按需容量，Fargate Spot 则提供竞价型容量。您启动任务时，Amazon ECS 会为您预置 Fargate 资源。此 Fargate 资源附带的内存和 CPU 单元直接对应您在任务定义中声明的任务级别限制。每个任务都会获得自己的 Fargate 资源，从而在任务和计算资源之间建立 1:1 的关系。

在 Fargate Spot 上运行的任务可能会中断。在两分钟警告之后便会出现中断。这样的情况通常发生在需求旺盛的时期。Fargate Spot 最适合可容忍中断的工作负载，例如批处理作业、开发或暂存环境。它们还适用于不需要高可用性和低延迟的任何其他场景。

您可以在运行 Fargate 按需任务的同时运行 Fargate Spot 任务。通过将它们组合使用，您能以更低的成本获得预置容量爆增。

Amazon ECS 还可以为您的任务管理 Amazon EC2 实例容量。每个 Amazon EC2 容量提供程序都与您指定的 Amazon EC2 Auto Scaling 组关联。您使用 Amazon EC2 容量提供程序时，集群自动扩缩会保持 Amazon EC2 Auto Scaling 组的大小，确保可以放置所有计划任务。

# 为 Amazon ECS 选择 Fargate 任务大小
<a name="fargate-task-size-best-practice"></a>

对于 AWS Fargate 任务定义，您需要在任务级别指定 CPU 和内存，并且无需考虑任何开销。您还可以在容器级别为 Fargate 任务指定 CPU 和内存。但是，不需要执行此操作。资源限制必须大于或等于您声明的任何预留。在大多数情况下，您可以将它们设置为任务定义中声明的每个容器的预留总和。然后，将数字向上舍入到最接近的 Fargate 大小。有关可用大小的更多信息，请参阅[任务 CPU 和内存](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/fargate-tasks-services.html#fargate-tasks-size)。

# 在 Amazon EC2 上使用容量提供程序加快 Amazon ECS 集群的容量预置
<a name="capacity-cluster-speed-up-ec2-best-practice"></a>

在 Amazon EC2 上运行 Amazon ECS 的客户可以利用 [Amazon ECS Cluster Auto Scaling（CAS）](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-auto-scaling.html)来管理 Amazon EC2 Auto Scaling 组（ASG）的扩缩。使用 CAS，您可以将 Amazon ECS 配置为自动扩缩 ASG，您只需专注于运行任务即可。Amazon ECS 将确保 ASG 根据需要横向缩减和横向扩展，无需进一步干预。Amazon ECS 容量提供程序用于通过确保有足够的容器实例可以满足应用程序的需求来管理集群中的基础设施。要了解 Amazon ECS CAS 的工作方式，请参阅 [Deep Dive on Amazon ECS Cluster Auto Scaling](https://aws.amazon.com/blogs/containers/deep-dive-on-amazon-ecs-cluster-auto-scaling/)。

由于 CAS 依赖于与 ASG 基于 CloudWatch 的集成来调整集群容量，所以它具有与发布 CloudWatch 指标、指标 `CapacityProviderReservation` 突破 CloudWatch 警报（包括高警和低警报）所花费的时间以及新启动的 Amazon EC2 实例预热所花费的时间相关的固有延迟。您可以执行以下操作来提高 CAS 的响应能力，从而加快部署速度：

## 容量提供程序分步扩缩大小
<a name="cas-step-size"></a>

Amazon ECS 容量提供程序最终将增加/缩小容器实例，以满足您的应用程序需求。Amazon ECS 将启动的实例最小数量默认设置为 1。如果需要多个实例来放置待处理的任务，这可能会额外增加您的部署时间。您可以使用 Amazon ECS API 增加 [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ManagedScaling.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ManagedScaling.html)，以增加 Amazon ECS 一次横向缩减或扩展的最小实例数量。过低的 [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ManagedScaling.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ManagedScaling.html) 可能会限制一次横向缩减或扩展的容器实例数量，这可能会减慢您的部署速度。

**注意**  
此配置目前只能通过 [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateCapacityProvider.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateCapacityProvider.html) 或 [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateCapacityProvider.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateCapacityProvider.html) API 进行。

## 实例预热期
<a name="instance-warmup-period"></a>

实例预热期是新启动的 Amazon EC2 实例可以向自动扩缩组提供 CloudWatch 指标之后需要经过的时间。指定的预热期到期后，该实例将计入 ASG 的聚合指标，CAS 将继续进行下一次计算迭代，从而估计所需的实例数量。

[https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ManagedScaling.html#ECS-Type-ManagedScaling-instanceWarmupPeriod](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ManagedScaling.html#ECS-Type-ManagedScaling-instanceWarmupPeriod) 的默认值为 300 秒，您可以通过 [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateCapacityProvider.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateCapacityProvider.html) 或 [https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateCapacityProvider.html](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateCapacityProvider.html) API 将其配置为较低的值，以提高扩缩响应速度。

## 备用容量
<a name="spare-capacity"></a>

如果您的容量提供程序没有可用于放置任务的容器实例，则它需要通过即时启动 Amazon EC2 实例来增加（横向扩展）集群容量，并等待它们启动后才能在其上启动容器。这样会大大降低任务启动率。您在此有两种选择。

 在这种情况下，已经启动并准备好运行任务的备用 Amazon EC2 容量将提高有效的任务启动率。您可以使用 `Target Capacity` 配置来表示您希望在集群中维护备用容量。例如，通过将 `Target Capacity` 设置为 80%，表示您的集群始终需要 20% 的备用容量。此备用容量可使任何独立任务立即启动，从而确保任务启动不受限制。这种方法的代价是保持备用集群容量的潜在成本增加。

您可以考虑采用另一种方法，即为服务而不是容量提供程序增加余量。这意味着，与其减少 `Target Capacity` 配置以启动备用容量，不如修改服务自动扩缩的目标跟踪扩缩指标或分步扩缩阈值来增加服务中的副本数量。请注意，这种方法仅对高峰工作负载有帮助，但在部署新服务并第一次从 0 个任务增加到 N 个任务时不会产生任何影响。有关相关扩缩策略的更多信息，请参阅[目标跟踪扩缩策略](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-autoscaling-targettracking.html)或[分步扩缩策略](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-autoscaling-stepscaling.html)。