介绍
Escalator
是atlassian开源的自动弹性项目。该项目通过对k8s集群上workload的资源需求总量和Node Group中Node能提供的可用资源总量来计算使用率和扩缩容增量,并最终向Cloud Provider下发弹性伸缩的行为。另外,项目还提供了适用于Prometheus的metrics端点,方便从外部采集监控数据。需要强调的是,该项目针对的扩缩容目标是Node Group中的Node,而不是K8s层面的replicas数量。
为了对自动弹性伸缩行为做优化, Escalator对Node节点,除了做常规的up/down 之外,还是用了中间态的taint。同时,还在算法中指定了cool down时间等,从而保障算法的高效。
下文是对Escalator的扩容流程和核心算法的简单介绍。
扩容过程
- 获取节点组中的所有容器信息
- 获取节点组中的所有节点信息
- 将节点过滤为三类:
- tainted
- untaint
- cordoned
- 计算Pods的资源需求总量
- 计算untaints节点的可分配资源总量
- 使用资源需求总量与可分配资源总量计算使用率
- 如果存在扩容锁,等待扩容锁已被释放
- 确定CPU或内存利用率的较大者
- 确定扩缩容的行为:需要扩容,缩容或什么都不做?
- 如果需要扩容,计算需要增加的节点数量
- 按需要的节点数量扩容节点组
- 首先untaint节点
- 如果我们仍然需要更多节点,向云提供商发出请求以增加节点组
- 如果我们要求扩展云提供商,锁定扩容锁
算法与计算
假设
为了计算出资源需求,当前实例数,利用率和扩容的增量,Escalator作出了以下假设:
- 节点组中的所有节点拥有相同的可分配资源
- 节点组中的所有Pods的容器均指定了资源需求量
如果Escalator不能达成以上假设,比如,容器没有指定资源需求量,或者多个节点拥有不同的可分配资源,扩缩容行为可能产生意想不到的副作用
资源需求,容量和利用率
为了计算出节点组的扩容量,Escalator会计算节点组中的当前资源需求总量,并将其与节点组的当前实例数进行比较。
为此,节点组中Pods的所有容器的资源需求都被汇总起来。所有节点的可分配资源(容量)也汇总到一起。
然后比较这些资源请求总量与节点的可分配资源总量,并为CPU和内存生成百分比利用率。然后Escalator采用两者中的较高者(CPU和内存)并用于后续计算。
例如:
我们有 10 个分别只包含一个容器的pods, 每个容器指定了需要使用 500m
CPU 和 100mb
内存.
计算出来的资源需求总量就是(5000m
) CPU 和 1000mb
内存.
10 * 500m
= 5000m10 * 100mb
= 1000mb
我们有两个Node节点,其可分配的资源量均为 1 (1000m
) CPU 和 4000mb
内存.
计算出来的可分配资源总量为 2 (2000m
) CPU 和 8000mb
内存.
2 * 1000m
= 2000m2 * 4000mb
= 8000mb
于是,可以计算出资源使用率如下:
- CPU:
5000m / 2000m * 100
= 250% - 内存:
1000mb / 8000mb * 100
= 12.5%
然后,我们采用更高的百分比利用率,在这种情况下, CPU: 250%.
根据这个数字,我们可以扩容、缩容或者什么都不做。这取决于配置的阈值。
扩容增量的计算
当确定Escalator需要扩容节点组后,需要计算并告知云提供商扩容节点组的数量。
扩容增量是通过百分比减少公式来计算的。我们需要通过计算将利用率降低到scale_up_threshold_percent
选项所需的节点数,这个节点数就是增加节点组的数量。
例如:
scale_up_threshold_percent
是70
- CPU利用率是
250
(250 - 70) / 70
=2.57142857143
2.57142857143 * 2 nodes
=5.14285714286
- 扩容总量为:
ceil(5.14285714286)
=6
个节点
通过向云提供商请求将节点组再扩展6个节点后,新的总节点数将变为8个。当新节点数变为8个时,节点组利用率如下:
使用率将按如下计算:
- CPU:
5000m / 8000m * 100
= 62.5% - 内存:
1000mb / 32000mb * 100
= 3.125%
Daemonsets
Daemonsets运行在所有Node节点上,它有意被排除在Escalator执行的利用率计算之外的。主要是基于以下原因:
- 只关注具有node selector或node affinity的Pods,可以简化利用率的计算。
- 无法简单的选择节点组中运行的Daemonsets,因为它们没有node selector或node affinity。
- 无法简单的计算出在新扩容节点上Daemonsets的利用率。