参考资料
ECS Cluster Auto Scaling (CAS)是一项面向ECS的全新功能,专门用于管理EC2 Auto Scaling Groups (ASG)的伸缩工作
CAS以ECS容量提供程序(ECS Capacity Provider)为基础,后者负责提供ECS集群与所使用ASG之间的联接。每个ASG与单一容量提供程序相关联——每个容量提供程序只能对应一个ASG,但我们可以将多个容量提供程序关联到同一个ECS集群
CAS的三个核心目的
- 只要ASG没有充足的容量运行客户尝试执行的任务,CAS就应及时对ASG进行横向扩展(添加更多实例)。
- 只要不会导致任何任务中断(除后台守护程序以外),CAS就应进行收缩(移除实例)。
- 客户应保持对ASG的完全控制能力,包括设置容量的最小与最大值,使用其他伸缩策略以及配置实例类型等。
核心伸缩逻辑
M为客户可能需要的实例数量(运行所有ECS任务所需要的数量),N为正在运行的实例数量
- N=M,则不需要进行容量增加
- N<M,则代表当前正在运行的实例少于需求实例,因此需要进行扩展
- N>M,则代表可以进行容量收缩(但不一定必要)
为了实现目标,ecs发布了一个名为CapacityProviderReservation
的新指标
C
a
p
a
c
i
t
y
P
r
o
v
i
d
e
r
R
e
s
e
r
v
a
t
i
o
n
=
M
÷
N
×
100
CapacityProviderReservation = M \div N \times 100
CapacityProviderReservation=M÷N×100
M代表CAS能够控制的部分,但是受所需任务数量(正在运行以及等待运行的任务)影响。
开启容量提供者之后,新启动的任务不会由于ecs集群中资源不足而失败,而是会进入provision状态
每个集群能够支持最多100个任务处于置备状态,置备任务会等待所需的资源10到30分钟。之后如果仍未获得必要的实例资源,则任务状态将转为“停止”、不再进行任何运行尝试
问题在于M值如何确定
绿色方框代表的是非守护程序任务,蓝色方框代表的则是守护程序任务
(1)如果每个实例都至少运行有一项任务(不包括守护程序服务任务),且不存在处于置备状态的任务,则M=N=3
(2)如果至少存在1个处于置备状态的任务,则M>N=3
(3)如果至少有一个实例未运行任何任务(守护程序服务任务除外),而且不存在任何置备状态任务,则M<N
由于不同的任务有着不同的资源需求、位置约束以及部署策略,而ASG本身也可能包含配备着不同vCPU、内存及其他可用资源容量的多种实例类型。实际上无法计算出M的精确值
CAS会通过以下方式计算出最佳的估算值
- 对所有置备任务进行分组,保证每个组都拥有相同的资源需求。
- 获取ASG中各新添加实例的具体类型与资源属性。
- 对于资源需求量相同的各个组,如果需要使用
binpack
部署策略,则计算所需的总实例数(部署策略不能更改所需实例数的下限,只能更改这些实例上的具体任务分布方式)。此项计算应考虑到任务与实例的vCPU、内存、ENI、端口以及GPU资源量以及任务部署约束。 - 取第3步计算中得出的最大值,作为各任务组中的M值。
- 最后,要求M>=N +
minimumScalingStepSize
且M <= N +maximumScalingStepSize
- 如果M与N均为0,
CapacityProviderReservation
=100,集群中不需要实例 - 如果M>0且N=0,
CapacityProviderReservation
=200,当前没有实例但需要运行任务
以上方式计算出的M值,通常为所需实例数的下限;有时候结果也正好就是所需实例的最佳值
第二个问题在于为何不直接将M设定为N?因为ecs需要给与客户自由度使用其他的扩缩策略。具体操作为
- 为ASG创建一项容量伸缩计划。
- 创建一项目标跟踪伸缩策略,并将其添加至容量伸缩计划当中。容量伸缩计划将通过由ECS面向各ASG容量提供程序发布的新CloudWatch指标
CapacityProviderReservation
实现托管容量伸缩(也可以同时引入其他扩展策略,将其添加至容量伸缩计划当中,甚至可以选择使用EC2预测性容量伸缩功能)。 - 定期(每分钟一次)发布
CapacityProviderReservation
指标。 - 管理实例终止保护,防止运行有非守护程序任务的实例因ASG伸缩操作而意外中断
目标跟踪伸缩策略
目标跟踪伸缩策略能够管理ASG的容量
-
如果M与N均为0,
CapacityProviderReservation
=100,集群中不需要实例 -
如果M>0且N=0,
CapacityProviderReservation
=200,当前没有实例但需要运行任务 -
Target capacity
小于100时,ASG中会有空闲容量。如果将目标值设置为50,伸缩策略会将N调整至CAS预计运行所有任务所需要的实例数量的2倍,意味着集群中有一半实例不运行任何任务 -
目标值越小,ASG中的空闲容量就越大
容量缩减与终止保护
当伸缩策略减小N时,其只能调整实例数量,却无法控制集群到底终止哪个实例。ASG也可能默认关闭掉某个正在运行任务的实例——托管终止保护的作用在于避免这一情况
在启用容量提供程序的前提下,ECS会防止集群终止任何运行有至少1个非守护程序任务的实例
在托管终止保护的支持下,ECS能够防止ASG在伸缩操作当中终止运行有非守护程序任务的实例,从而避免当前运行任务的意外中断
容量伸缩实操
扩展与收缩的完整示例如下
容量扩展
第一步。集群包含一个容量提供程序,ASG中包含3个实例(如上所示),且所有实例都在运行任务。启用了目标容量为100的托管容量伸缩,同时启用了托管终止保护选项。集群中只运行了一个任务定义,意味着全部任务都具有相同的资源要求。此时M = 3,N = 3,且CapacityProviderReservation
= 100。
第二步。调用RunTask以额外添加9项任务。其中6项运行在现有实例之上,另外3项则处于置备状态。现在,M = 4,N = 3,CapacityProviderReservation
= 133。指标变化如下图所示。
第三步。一旦指标超过预设的目标值100,则伸缩策略开始执行,将所需的ASG数量从N = 3上调至N = 4。由于ECS还没有进行任务分配,所以这时任务仍暂时处于置备状态。
第四步。ECS识别出可用的额外容量,并将置备任务放置在新的实例上。
第五步。指标更新后,由于M = 4而且N = 4,因此CapacityProviderReservation
= 100。不再需要进一步的容量伸缩。
容量收缩
第一步。与容量扩展的第一步相同。集群包含一个容量提供程序,ASG中包含3个实例(如上所示),且所有实例都在运行任务。启用了目标容量为100的托管容量伸缩,同时启用了托管终止保护选项。集群中只运行了一个任务定义,意味着全部任务都具有相同的资源要求。此时M = 3,N = 3,且CapacityProviderReservation
= 100。
第二步。停止其中一项任务(例如,由于服务的伸缩带来的任务停止)。现在,前2个实例中仍存在非守护程序任务,因此不会被终止;但第3个实例已经不符合保护标准。但由于尚未触发容量伸缩操作,因此3个实例仍在继续运行。
第三步。现在,其中1个实例上已经不存在任何非守护程序任务,因此伸缩指标被更新为:M = 2, N = 3, 因此CapacityProviderReservation
= 66。
第四步。15分钟之后(即经过连续15次检测后,指标值仍然为66),ASG触发容量收缩。由于第3个实例不符合保护条件,因此会被终止。这也保证了容量收缩期间,现有任务不会受到任何影响。
第五步。现在,该实例已经被终止,指标再次更新:N = 2, M = 2, 因此CapacityProviderReservation
= 100。不需要进行进一步容量伸缩。