Administrator
Published on 2026-05-01 / 16 Visits
0
0

真正理解 ECS Fargate:自动扩缩容、负载均衡与可观测性

大家好,今天想分享一次关于 Amazon ECS Fargate 的完整实践。

这次学习主要围绕几个问题展开:

  • ECS 到底如何运行工作负载?

  • 自动扩缩容实际是怎样工作的?

  • 为什么任务数量增加了,流量却不一定会被分散?

  • 为什么没有可观测性,就很难理解系统的真实状态?

  • 为什么一个可弹性伸缩的生产服务通常还需要 ALB?

这些结论并不只是来自文档,而是来自一套真实运行的 ECS 服务,以及在实际压测、扩容和监控过程中观察到的行为。

一、先理解 ECS 的基本结构

ECS 的资源关系可以简化为:

Cluster
 └── Service
      └── Task
           └── Container

中文可以理解为:

集群
 └── 服务
      └── 任务
           └── 容器

这几个概念经常一起出现,但它们的职责并不相同。

Cluster:资源和服务的逻辑边界

Cluster 是 ECS 中组织服务和任务的逻辑空间。

使用 ECS EC2 模式时,Cluster 中还包含实际的 EC2 计算资源;使用 Fargate 时,底层服务器由 AWS 管理,我们主要看到的是运行在 Cluster 中的 Service 和 Task。

Service:维持服务的期望状态

Service 负责确保指定数量的 Task 持续运行。

例如,Service 的 Desired Count 设置为 3,就代表我们希望 ECS 始终维持 3 个 Task。

如果其中一个 Task 异常退出,Service 会自动启动新的 Task,将运行数量恢复到 3。

Service 还可以连接:

  • Application Load Balancer

  • Target Group

  • Service Auto Scaling

  • 滚动部署策略

  • 健康检查机制

因此,Service 更像是应用在 ECS 中的长期运行管理器。

Task:ECS 的最小调度单位

Task 是 ECS 实际调度的基本单位。

一个 Task 会定义:

  • CPU 和内存

  • 网络配置

  • 独立 IP 和 ENI

  • 启动与停止生命周期

  • 一个或多个 Container

ECS 调度的是 Task,而不是单独调度 Task 内部的 Container。

如果一个 Task 中包含多个 Container,这些 Container 通常会作为一个整体启动、运行和停止。

从概念上看,可以进行这样的类比:

ECS Task ≈ Kubernetes Pod

两者并不完全相同,但都可以被理解为一组共同运行、共享部分资源和生命周期的容器。

Container:Task 中真正运行的进程

Container 是 Task 内部的具体运行单元。

它可能是:

  • Java 应用

  • Node.js 服务

  • Nginx

  • 日志采集 Sidecar

  • 监控 Agent

所以更准确地说,ECS Service 管理 Task,Task 中再运行一个或多个 Container。

二、ECS Fargate、ECS EC2 和 EC2 ASG 有什么区别?

这三种模式的核心区别,在于“扩容时增加的是什么”以及“谁负责管理服务器”。

模式

扩容对象

服务器由谁管理

EC2 Auto Scaling Group

EC2 实例

用户

ECS EC2

EC2 实例和 ECS Task

用户

ECS Fargate

ECS Task

AWS

EC2 Auto Scaling Group

在普通 EC2 ASG 模式下,扩容意味着增加 EC2 实例。

用户仍然需要管理:

  • AMI

  • 实例类型

  • 操作系统

  • 安全补丁

  • 磁盘

  • 实例容量

  • 应用部署

ECS EC2

在 ECS EC2 模式下,应用以 Task 的形式运行,但 Task 仍然需要被调度到用户管理的 EC2 实例上。

因此需要同时关注两层容量:

  • ECS Service 是否有足够的 Task

  • ECS Cluster 是否有足够的 EC2 资源运行这些 Task

即使 Service 希望启动更多 Task,如果 Cluster 中没有足够的 CPU 或内存,新任务仍然无法正常运行。

ECS Fargate

Fargate 隐藏了底层服务器。

用户不需要直接管理:

  • EC2 实例类型

  • AMI

  • 操作系统

  • 系统补丁

  • ECS 集群主机容量

我们只需要声明:

  • 每个 Task 需要多少 CPU

  • 每个 Task 需要多少内存

  • 希望运行多少个 Task

  • 使用什么镜像

  • 网络和安全组如何配置

AWS 负责为这些 Task 提供底层计算资源。

因此,Fargate 常被称为 Serverless Compute。

不过,“Serverless”并不意味着完全不需要容量规划。我们仍然需要选择合适的 Task CPU 和内存、设置扩缩容范围,并关注账户配额。

Fargate 消除的是服务器管理工作,而不是应用架构和容量设计责任。

三、ECS Service Auto Scaling 实际做了什么?

这是整个实践中最重要的认识之一:

ECS Service Auto Scaling 只负责调整 Task 数量,不负责在 Task 之间重新分配已经存在的工作负载。

一个典型的扩容流程是:

Service 平均 CPU 升高
        ↓
触发扩容策略
        ↓
增加 Service Desired Count
        ↓
ECS 启动新的 Task

扩容过程中,ECS 不会:

  • 将旧 Task 中的线程迁移到新 Task

  • 把正在处理的请求转移给新 Task

  • 自动重新分配已有长连接

  • 主动将热点工作负载拆分到其他 Task

这就解释了测试中观察到的一个现象:

Task A:CPU 很高
Task B:几乎空闲
Task C:几乎空闲

新 Task 已经成功启动,但原来的流量仍然集中在 Task A 上。

与此同时,由于 ECS Service 的 CPU 指标通常是所有 Task 的平均值,新 Task 加入后,平均 CPU 会下降。

例如:

扩容前:

Task A CPU = 90%
Service 平均 CPU = 90%

扩容后:

Task A CPU = 90%
Task B CPU = 5%
Task C CPU = 5%

Service 平均 CPU ≈ 33%

如果扩容阈值是 60%,Service 平均 CPU 已经降到阈值以下,系统就不会继续扩容。

这并不是 ECS 出错了,而是自动扩缩容策略在按照指标正常工作。

真正的问题是:新增容量是否能够接收到流量?

四、Auto Scaling 是控制系统,不是一次性触发器

在实践中,容易把自动扩缩容理解成一个简单的条件判断:

CPU 超过阈值
→ 增加 Task

但它更接近一个持续运行的反馈控制系统。

它会不断观察:

  • 当前指标

  • 目标值

  • Service Desired Count

  • 最大和最小容量

  • 扩容冷却时间

  • 缩容冷却时间

  • 新 Task 启动后的平均指标变化

系统会根据反馈持续调整 Task 数量。

因此,不能只看到“CPU 超过阈值”就认为一定会无限扩容。新 Task 启动后,即使没有真正承担多少工作,也可能拉低 Service 的平均 CPU,从而让指标回到目标范围。

这也是为什么设计扩缩容策略时,不能只关注配置是否生效,还必须理解指标的统计维度。

五、Service、Task 和 Container 指标有什么区别?

最开始进行测试时,我们只能看到 ECS 默认提供的指标,例如:

  • Cluster 级 CPU 和内存

  • Service 级平均 CPU 和内存

但无法直接看到每个 Task 的资源使用情况。

这带来了一个很实际的问题。

虽然系统已经从 1 个 Task 扩容到了 3 个 Task,但我们无法确认:

  • 新 Task 是否真的开始处理请求

  • 三个 Task 的 CPU 是否接近

  • 流量是否仍然集中在原来的 Task

  • 是单个容器过载,还是整个 Service 都在繁忙

只看 Service 平均值,很容易得到错误的结论。

例如,一个 Task 的 CPU 已经接近 100%,但另外两个 Task 几乎没有负载。Service 平均值看起来可能仍然很正常。

平均值告诉我们整个服务的总体状态,却可能隐藏单个 Task 的热点问题。

六、Container Insights 与增强可观测性

为了查看 Task 和 Container 级别的运行状态,需要为 ECS 启用 Container Insights。

开启增强可观测性后,可以在 CloudWatch 的 ECS/ContainerInsights 命名空间中查看更细粒度的数据,包括:

  • Task CPU 使用情况

  • Container CPU 使用情况

  • Task 内存使用情况

  • Container 内存使用情况

  • Task 和 Container 的运行状态

开启后,系统的真实情况立刻变得清晰:

Task A:CPU 使用率很高
Task B:基本空闲
Task C:基本空闲

这证明 ECS 确实完成了扩容,但流量没有被有效分配到新增 Task。

可观测性的价值就在这里。

没有 Task 级指标时,我们只能知道“Service 平均 CPU 已经下降”;有了详细指标后,我们才能知道平均值为什么下降,以及新增 Task 是否真正承担了工作。

这些数据对于以下场景非常重要:

  • 调试扩缩容行为

  • 判断流量是否均匀

  • 定位单个 Task 的性能问题

  • 发现内存泄漏或热点实例

  • 验证负载均衡是否生效

  • 评估 CPU 和内存配置是否合理

在分布式系统中,可观测性并不是上线后的附加功能,而是理解系统行为的必要条件。

七、为什么只有 Auto Scaling 还不够?

Auto Scaling 增加的是容量,不是流量分发能力。

假设客户端直接连接到某个 ECS Task:

Client
  ↓
Task A 的 IP

当 Task A 负载升高后,Auto Scaling 启动了 Task B 和 Task C:

Task A:正在接收流量
Task B:已启动,但没有流量
Task C:已启动,但没有流量

如果客户端仍然使用原来的 Task A IP,所有请求就会继续进入 Task A。

新增 Task 虽然存在,却没有稳定的入口让流量到达它们。

类似的问题还可能出现在:

  • 客户端直接访问 Task IP

  • 应用缓存了某个固定地址

  • DNS 解析结果被长时间缓存

  • 长连接始终停留在原来的 Task

  • 上游系统没有服务发现或负载均衡能力

因此:

自动扩缩容解决的是“有没有足够的计算容量”,负载均衡解决的是“流量能不能使用这些容量”。

两者缺一不可。

八、为什么生产服务通常需要 ALB?

对于基于 HTTP 或 HTTPS 的 ECS 服务,Application Load Balancer 是一种常见的生产入口方案。

加入 ALB 后,请求链路变成:

客户端
  ↓
ALB(稳定的 DNS 地址)
  ↓
Target Group(IP 模式)
  ↓
ECS Tasks

ALB 带来的关键能力包括:

  • 提供稳定的访问入口

  • 自动将新 Task 注册到 Target Group

  • 自动移除已经停止的 Task

  • 通过健康检查排除异常目标

  • 在健康 Task 之间分发请求

  • 支持 HTTPS 和 ACM 证书

  • 支持基于域名或路径的转发规则

当 ECS Service 扩容时,新 Task 会被自动注册到 Target Group。

健康检查通过后,ALB 就可以开始向它分发请求。

当某个 Task 被停止时,它会进入 Deregistration Draining 阶段。ALB 停止向它发送新请求,并尽量让正在处理的请求完成,然后再将其移出 Target Group。

只有将 ECS Service Auto Scaling 与稳定的流量入口结合起来,才能形成完整的弹性闭环:

负载升高
  ↓
指标超过目标值
  ↓
ECS 增加 Task
  ↓
新 Task 通过健康检查
  ↓
ALB 将请求分发到新 Task
  ↓
单个 Task 的压力下降

因此,更准确的说法是:

Auto Scaling 让计算资源具备弹性,负载均衡让流量能够真正使用这些弹性资源。

对于 HTTP 服务,ALB 是最常见的选择;其他场景也可能使用 NLB、服务发现、API Gateway 或 Service Connect,具体取决于协议和架构需求。

九、Fargate 网络设计中的重要经验

Fargate Task 通常使用 awsvpc 网络模式。

每个 Task 都会获得自己的 ENI 和私有 IP。这些 IP 可能随着任务停止、重建和重新部署而变化。

因此,直接使用 Task IP 作为生产访问入口并不可靠。

更加常见的生产网络设计是:

Internet
  ↓
ALB(公有子网)
  ↓
ECS Tasks(私有子网)

推荐配置包括:

  • ALB 部署在公有子网

  • ECS Task 部署在私有子网

  • Task 不分配公网 IP

  • ALB Security Group 对外开放 80 或 443

  • Task Security Group 只允许来自 ALB Security Group 的应用端口流量

例如,应用监听 3000 端口时:

ALB Security Group
入站:HTTPS 443,来源为公网

Task Security Group
入站:TCP 3000,来源为 ALB Security Group

这样,用户只能通过 ALB 访问应用,无法绕过 ALB 直接连接 Task。

这种设计不仅解决了动态 IP 问题,也缩小了服务暴露面。

如果私有子网中的 Task 需要拉取镜像、访问外部 API 或下载依赖,还需要合理配置 NAT Gateway 或相应的 VPC Endpoint。

十、实际观察到的扩容过程

在这次测试中,我们观察到了一个完整的扩容过程:

  1. Service 最初只有 1 个 Task

  2. 压测请求集中进入这个 Task

  3. 该 Task 的 CPU 快速升高

  4. Service Auto Scaling 被触发

  5. Desired Count 从 1 增加到 3

  6. 新 Task 在较短时间内启动

  7. Service 平均 CPU 随之下降

  8. 系统不再继续扩容

  9. 但原有负载仍然集中在第一个 Task

这次测试验证了几个关键结论:

  • ECS Auto Scaling 确实能够根据指标调整 Task 数量

  • 新增 Task 不代表已有流量会自动迁移

  • Service 平均指标可能掩盖单个 Task 的高负载

  • 没有负载均衡时,扩容可能只增加空闲容量

  • 没有 Task 级监控时,很难看清这些现象

所以,判断扩缩容是否真正有效,不能只看 Desired Count 是否变化。

还需要同时验证:

  • 新 Task 是否成功启动

  • 健康检查是否通过

  • 新 Task 是否开始接收请求

  • 各 Task 的资源使用是否合理

  • 响应时间和错误率是否改善

十一、如何停止 Fargate Task,避免继续产生计算费用?

如果只是暂时停止测试,又希望保留 ECS Service、Task Definition 和其他基础设施,可以将 Service 的 Desired Count 设置为 0。

操作逻辑是:

ECS Service
  ↓
Update Service
  ↓
Desired Count = 0

同时还需要确认 Service Auto Scaling 的最小容量也设置为 0。

否则,自动扩缩容策略可能重新将 Desired Count 提升到 1 或更高。

设置完成后:

  • 所有 Fargate Task 会停止

  • 不再产生这些 Task 对应的 Fargate 计算费用

  • ECS Service 会继续保留

  • Task Definition 会继续保留

  • 后续可以重新将 Desired Count 调高

需要注意,这并不代表整套架构完全不再产生费用。

以下资源仍可能继续计费:

  • Application Load Balancer

  • NAT Gateway

  • CloudWatch 日志和指标

  • ECR 镜像存储

  • 公网 IPv4 地址

  • 其他关联网络资源

因此,如果目标是完全停止测试环境成本,还需要逐项检查外围基础设施。

十二、这次实践的核心结论

通过这次测试,可以将 ECS Fargate 的关键行为总结为以下几点。

ECS 扩展的是 Task,而不是工作负载

ECS 可以启动更多 Task,但不会自动迁移线程、长连接或已经进入某个 Task 的请求。

Fargate 消除的是服务器管理,而不是架构责任

AWS 管理底层主机,但用户仍然需要设计 Task 规格、网络、健康检查、流量入口和扩缩容策略。

Auto Scaling 只增加容量

如果没有负载均衡或服务发现,新增 Task 可能完全接收不到流量。

平均指标可能掩盖局部问题

Service 平均 CPU 下降,不代表原有热点 Task 的负载已经下降。

可观测性是理解系统行为的前提

只有看到 Task 和 Container 级别的数据,才能判断扩容后流量是否真正被分散。

ALB 补全了 HTTP 服务的弹性闭环

ECS Service Auto Scaling 负责提供更多计算资源,ALB 负责把请求分发到这些资源上。

十三、从“会用 ECS”到理解 ECS

这次实践弥补了“知道如何配置 ECS”和“理解 ECS 在真实负载下如何运行”之间的差距。

以前看到生产环境同时运行多个 Task,很容易觉得系统是不是配置得过多。

但实践之后会发现,系统保留一定冗余,可能是在为以下情况做准备:

  • 流量突然增加

  • 单个 Task 发生故障

  • 应用进行滚动部署

  • 可用区出现异常

  • 新 Task 需要时间启动并通过健康检查

同样,配置了 Auto Scaling,也不代表负载天然就是均匀的。

Task 数量、流量分配和指标观测,是三个相互关联但职责不同的问题:

Auto Scaling
解决容量问题

Load Balancing
解决流量分配问题

Observability
解决系统是否按预期运行的问题

最终,我对 ECS Fargate 的理解可以概括为:

Fargate 帮助我们摆脱服务器管理,ECS Service 负责维持任务数量,Auto Scaling 负责动态调整容量,ALB 负责分配流量,而可观测性帮助我们确认这一整套机制是否真正有效。

只有这些部分共同工作,系统才真正具备生产级的弹性能力。


Comment