Escalator

介绍

Escalator是atlassian开源的自动弹性项目。该项目通过对k8s集群上workload的资源需求总量和Node Group中Node能提供的可用资源总量来计算使用率和扩缩容增量,并最终向Cloud Provider下发弹性伸缩的行为。另外,项目还提供了适用于Prometheus的metrics端点,方便从外部采集监控数据。需要强调的是,该项目针对的扩缩容目标是Node Group中的Node,而不是K8s层面的replicas数量。

为了对自动弹性伸缩行为做优化, Escalator对Node节点,除了做常规的up/down 之外,还是用了中间态的taint。同时,还在算法中指定了cool down时间等,从而保障算法的高效。

下文是对Escalator的扩容流程和核心算法的简单介绍。

扩容过程

  1. 获取节点组中的所有容器信息
  2. 获取节点组中的所有节点信息
  3. 将节点过滤为三类:
    • tainted
    • untaint
    • cordoned
  4. 计算Pods的资源需求总量
  5. 计算untaints节点的可分配资源总量
  6. 使用资源需求总量与可分配资源总量计算使用率
  7. 如果存在扩容锁,等待扩容锁已被释放
  8. 确定CPU或内存利用率的较大者
  9. 确定扩缩容的行为:需要扩容,缩容或什么都不做?
  10. 如果需要扩容,计算需要增加的节点数量
  11. 按需要的节点数量扩容节点组
    • 首先untaint节点
    • 如果我们仍然需要更多节点,向云提供商发出请求以增加节点组
    • 如果我们要求扩展云提供商,锁定扩容锁

算法与计算

假设

为了计算出资源需求,当前实例数,利用率和扩容的增量,Escalator作出了以下假设:

  • 节点组中的所有节点拥有相同的可分配资源
  • 节点组中的所有Pods的容器均指定了资源需求量

如果Escalator不能达成以上假设,比如,容器没有指定资源需求量,或者多个节点拥有不同的可分配资源,扩缩容行为可能产生意想不到的副作用

资源需求,容量和利用率

为了计算出节点组的扩容量,Escalator会计算节点组中的当前资源需求总量,并将其与节点组的当前实例数进行比较。

为此,节点组中Pods的所有容器的资源需求都被汇总起来。所有节点的可分配资源(容量)也汇总到一起。

然后比较这些资源请求总量与节点的可分配资源总量,并为CPU和内存生成百分比利用率。然后Escalator采用两者中的较高者(CPU和内存)并用于后续计算。

例如:

我们有 10 个分别只包含一个容器的pods, 每个容器指定了需要使用 500m CPU 和 100mb 内存.
计算出来的资源需求总量就是(5000m) CPU 和 1000mb 内存.

  • 10 * 500m = 5000m
  • 10 * 100mb = 1000mb

我们有两个Node节点,其可分配的资源量均为 1 (1000m) CPU 和 4000mb 内存.
计算出来的可分配资源总量为 2 (2000m) CPU 和 8000mb 内存.

  • 2 * 1000m = 2000m
  • 2 * 4000mb = 8000mb

于是,可以计算出资源使用率如下:

  • CPU: 5000m / 2000m * 100 = 250%
  • 内存: 1000mb / 8000mb * 100 = 12.5%

然后,我们采用更高的百分比利用率,在这种情况下, CPU: 250%.

根据这个数字,我们可以扩容、缩容或者什么都不做。这取决于配置的阈值。

扩容增量的计算

当确定Escalator需要扩容节点组后,需要计算并告知云提供商扩容节点组的数量。

扩容增量是通过百分比减少公式来计算的。我们需要通过计算将利用率降低到scale_up_threshold_percent选项所需的节点数,这个节点数就是增加节点组的数量。

例如:

  • scale_up_threshold_percent70
  • 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的利用率。
0%