6 分钟阅读
EffectiveHorizontalPodAutoscaler(简称 EHPA)是 Crane 提供的弹性伸缩产品,它基于社区 HPA 做底层的弹性控制,支持更丰富的弹性触发策略(预测,观测,周期),让弹性更加高效,并保障了服务的质量。
一个简单的 EHPA yaml 文件如下:
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef: #(1)
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1 #(2)
maxReplicas: 10 #(3)
scaleStrategy: Auto #(4)
metrics: #(5)
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
prediction: #(6)
predictionWindowSeconds: 3600 #(7)
predictionAlgorithm:
algorithmType: dsp
dsp:
sampleInterval: "60s"
historyLength: "3d"
大多数在线应用的负载都有周期性的特征。我们可以根据按天或者按周的趋势预测未来的负载。EHPA 使用 DSP 算法来预测应用未来的时间序列数据。
以下是一个开启了预测能力的 EHPA 模版例子:
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
spec:
prediction:
predictionWindowSeconds: 3600
predictionAlgorithm:
algorithmType: dsp
dsp:
sampleInterval: "60s"
historyLength: "3d"
在使用预测算法预测时,你可能会担心预测数据不准带来一定的风险,EHPA 在计算副本数时,不仅会按预测数据计算,同时也会考虑实际监控数据来兜底,提升了弹性的安全性。
实现的原理是当你在 EHPA 中定义 spec.metrics
并且开启弹性预测时,EffectiveHPAController 会在创建底层管理的 HPA 时按策略自动生成多条 Metric Spec。
例如,当用户在 EHPA 的 yaml 里定义如下 Metric Spec:
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
spec:
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
它会自动转换成两条 HPA 的阈值配置:
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
spec:
metrics:
- pods:
metric:
name: crane_pod_cpu_usage
selector:
matchLabels:
autoscaling.crane.io/effective-hpa-uid: f9b92249-eab9-4671-afe0-17925e5987b8
target:
type: AverageValue
averageValue: 100m
type: Pods
- resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
type: Resource
在上面这个例子中,用户在 EHPA 创建的 Metric 阈值配置会自动转换成底层 HPA 上的两条 Metric 阈值配置:预测 Metric 阈值和实际监控 Metric 阈值
HPA 在配置了多个弹性 Metric 阈值时,在计算副本数时会分别计算每条 Metric 对应的副本数,并选择最大的那个副本数作为最终的推荐弹性结果。
整体流程图如下:
我们通过一个生产环境的客户案例来介绍 EHPA 的落地效果。
我们将生产上的数据在预发环境重放,对比使用 EHPA 和社区的 HPA 的弹性效果。
下图的红线是应用在一天内的实际 CPU 使用量曲线,我们可以看到在8点,12点,晚上8点时是使用高峰。绿线是 EHPA 预测的 CPU 使用量。
下图是对应的自动弹性的副本数曲线,红线是社区 HPA 的副本数曲线,绿线是 EHPA 的副本数曲线。
可以看到 EHPA 具有以下优势:
EHPA 提供了两种弹性策略:Auto
和 Preview
。用户可以随时切换它并立即生效。
Auto 策略下 EHPA 会自动执行弹性行为。默认 EHPA 的策略是 Auto。在这个模式下 EHPA 会创建一个社区的 HPA 对象并自动接管它的生命周期。我们不建议用户修改或者控制这个底层的 HPA 对象,当 EHPA 被删除时,底层的 HPA 对象也会一并删除。
Preview 策略提供了一种让 EHPA 不自动执行弹性的能力。所以你可以通过 EHPA 的 desiredReplicas 字段观测 EHPA 计算出的副本数。用户可以随时在两个模式间切换,当用户切换到 Preview 模式时,用户可以通过 spec.specificReplicas
调整应用的副本数,如果 spec.specificReplicas
为空,则不会对应用执行弹性,但是依然会执行副本数的计算。
以下是一个配置成 Preview 模式的 EHPA 模版例子:
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
spec:
scaleStrategy: Preview # ScaleStrategy indicate the strategy to scaling target, value can be "Auto" and "Preview".
specificReplicas: 5 # SpecificReplicas specify the target replicas.
status:
expectReplicas: 4 # expectReplicas is the calculated replicas that based on prediction metrics or spec.specificReplicas.
currentReplicas: 4 # currentReplicas is actual replicas from target
EHPA 从设计之出就希望和社区的 HPA 兼容,因为我们不希望重新造一个类似 HPA 的轮子,HPA 在不断演进的过程已经解决了很多通用的问题,EHPA 希望在 HPA 的基础上提供更高阶的 CRD,EHPA 的功能是社区 HPA 的超集。
EHPA 也会持续跟进支持 HPA 的新功能。
EHPA 的 Status 包括了自身的 Status 同时也汇聚了底层 HPA 的部分 Status。
以下是一个 EHPA 的 Status yaml例子:
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
status:
conditions:
- lastTransitionTime: "2021-11-30T08:18:59Z"
message: the HPA controller was able to get the target's current scale
reason: SucceededGetScale
status: "True"
type: AbleToScale
- lastTransitionTime: "2021-11-30T08:18:59Z"
message: Effective HPA is ready
reason: EffectiveHorizontalPodAutoscalerReady
status: "True"
type: Ready
currentReplicas: 1
expectReplicas: 0
EffectiveHorizontalPodAutoscaler 支持基于 cron 的自动缩放。
除了基于监控指标,有时节假日和工作日的工作负载流量存在差异,简单的预测算法可能效果不佳。然后可以通过设置周末 cron 来支持更大数量的副本来弥补预测的不足。
对于一些非 web 流量的应用,比如一些应用不需要在周末使用,可以把工作负载的副本数减少到 1,也可以配置 cron 来降低你的服务成本。
以下是 EHPA Spec
中的 cron 主要字段:
CronSpec
:可以设置多个 cron 自动伸缩配置,cron cycle 可以设置循环的开始时间和结束时间,并且工作负载的副本数可以在时间范围内持续保持为设定的目标值。Name
:cron 标识符TargetReplicas
:此 cron 时间范围内工作负载的目标副本数。Start
:cron 的开始时间,标准 linux crontab 格式End
:cron 的结束时间,标准 linux crontab 格式一些云厂商和社区当前的 cron 自动缩放功能存在一些缺点。
下图显示了当前 EHPA cron 自动伸缩实现与其他 cron 能力的对比。
针对以上问题,EHPA 实现的 cron autoscaling 是在与 HPA 兼容的基础上设计的,cron 作为 HPA 的一个指标,与其他指标一起作用于工作负载。
另外,cron 的设置也很简单。单独配置 cron 时,不在活动时间范围内时,不会对工作负载执行缩放。
假设你没有配置其他指标,你只需配置 cron 本身即可工作。
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
metadata:
name: php-apache-local
spec:
# ScaleTargetRef 关联到需扩缩容的工作负载
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1 # MinReplicas : autoscaler 缩放的最低副本数
maxReplicas: 100 # MaxReplicas : autoscaler 缩放的最大副本数
scaleStrategy: Auto # ScaleStrategy : 缩放工作负载时候,所采用的策略。可选值为 "Auto" "Manual"
# 最好将Cron Scheduling设置为一个完整的时间周期,例如: 一天,一周
# 下面是一天的Cron Scheduling
#(targetReplicas)
#80 -------- --------- ----------
# | | | | | |
#10 ------------ ----- -------- ----------
#(time) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#本地时区(timezone: "Local")意味着您使用运行Craned所在的服务器(或者可能是容器)的时区。例如,当Craned 是以UTC时区开始,那么它就是UTC。如果一开始是Asia/Shanghai,那么它就是Asia/Shanghai。
crons:
- name: "cron1"
timezone: "Local"
description: "scale down"
start: "0 0 ? * *"
end: "0 6 ? * *"
targetReplicas: 10
- name: "cron2"
timezone: "Local"
description: "scale up"
start: "0 6 ? * *"
end: "0 9 ? * *"
targetReplicas: 80
- name: "cron3"
timezone: "Local"
description: "scale down"
start: "00 9 ? * *"
end: "00 11 ? * *"
targetReplicas: 10
- name: "cron4"
timezone: "Local"
description: "scale up"
start: "00 11 ? * *"
end: "00 14 ? * *"
targetReplicas: 80
- name: "cron5"
timezone: "Local"
description: "scale down"
start: "00 14 ? * *"
end: "00 17 ? * *"
targetReplicas: 10
- name: "cron6"
timezone: "Local"
description: "scale up"
start: "00 17 ? * *"
end: "00 20 ? * *"
targetReplicas: 80
- name: "cron7"
timezone: "Local"
description: "scale down"
start: "00 20 ? * *"
end: "00 00 ? * *"
targetReplicas: 10
CronSpec 具有以下字段:
UTC
时区。你可以将它设置为Local
,这将使用正在运行的Crane容器所在的时区。其实,你定义America/Los_Angeles
也是可以的。以上YAML定义,意味着一天当中,工作负载在每小时所需要保持的副本数。工作负载将会每天按照该规则执行。
#80 -------- --------- ----------
# | | | | | |
#1 ------------ ----- -------- ----------
#(time) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
记住不要设置开始时间在结束时间之后。
例如,当你设置以下内容时:
crons:
- name: "cron2"
timezone: "Local"
description: "scale up"
start: "0 9 ? * *"
end: "0 6 ? * *"
targetReplicas: 80
以上无效,因为开始总是晚于结束。
HPA 控制器始终根据工作负载所描述的副本数进行扩展,这意味着保留原有副本数不变。
cron 驱动和扩展过程有六个步骤:
EffectiveHPAController
创建 HorizontalPodAutoscaler
,它被注入到spec
中的external cron metrics
中。HPAController
从 KubeApiServer
读取 external cron metrics
KubeApiServer
将请求转发给 MetricAdapter
和 MetricServer
MetricAdapter
找到目标 hpa 的 cron scaler
,并检测 cron scaler
是否处于活动状态。这意味着当前时间介于 cron 开始和结束计划时间之间。它将返回TargetReplicas
中定义的CronSpec
。HPAController
计算所有 metrics 结果,并通过选择最大的一个为目标副本数。并由此创建一个新的scale replicas
。HPAController
使用 Scale Api
缩放目标使用 EHPA 时,用户可以只配置 cron metric,让 EHPA 用作 cron hpa。
一个 EHPA 的多个 crons 将转换为一个external metrics
。
HPA 将获取external metrics
并在协调时计算目标副本。当存在多个指标的工作负载时,HPA 将选择最大的副本数来扩展。
EffectiveHorizontalPodAutoscaler
兼容 HorizontalPodAutoscaler
(内置在 kubernetes)。因此,如果你为 HPA 配置了指标,例如 cpu 或内存,那么 HPA 将根据它观察到的实时指标对副本数进行扩展。
通过 EHPA,用户可以同时配置 CronMetric
、PredictionMetric
、OriginalMetric
。
我们强烈建议你配置所有维度的指标。它们分别代表 cron 副本、先前预测的副本、后观察的副本。
这是一个强大的功能。因为 HPA 总是选择由所有维度metrics
计算的最大副本进行扩展。
这将保证你工作负载的 QOS,当你同时配置三种类型的自动缩放时,根据实际观察到的指标计算的副本最大,然后它将使用最大的一个。
尽管由于某些意想不到的原因,导致由PredictionMetric
计算的副本更小。因此,你不必担心 QOS。
当metrics adapter
处理external cron metrics
请求时,metrics adapter
将执行以下步骤。
graph LR
A[Start] --> B{Active Cron?};
B -->|Yes| C(largest targetReplicas) --> F;
B -->|No| D{Work together with other metrics?};
D -->|Yes| G(minimum replicas) --> F;
D -->|No| H(current replicas) --> F;
F[Result workload replicas];
没有活跃的cron,有两种情况:
HPA Controller
选择由所有指标计算的最大副本(这是硬代码中的 hpa 默认策略),cron 会影响 hpa。所以我们应该在 cron 不活动时移除 cron 效果,它应该返回最小值。有活跃的cron。我们使用cron spec
中指定的最大目标副本。基本上,在同一时间段内不应有超过一个活跃的 cron,这不是最佳实践。
HPA 将获取cron external metrics
,然后它会自行计算副本数。
当你需要在午夜将工作负载副本数保持在最低限度,根据该需求配置了 cron。
你需要 HPA 来获取指标服务器观察到的真实指标,以根据实时观察到的指标进行扩展。
最后,你配置一个prediction-driven metric
,通过预测方式提前扩大规模并在末期缩小规模。
apiVersion: autoscaling.crane.io/v1alpha1
kind: EffectiveHorizontalPodAutoscaler
metadata:
name: php-apache-multi-dimensions
spec:
# ScaleTargetRef 关联到需扩缩容的工作负载
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1 # MinReplicas : 缩放的最小副本数
maxReplicas: 100 # MaxReplicas : 缩放的最大副本数
scaleStrategy: Auto # ScaleStrategy : 缩放工作负载时候,所采用的策略。可选值为 "Auto" "Manual"
# Metrics 包含了用于计算所需副本数的指标。
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
# Prediction 的配置定义了需要预测的资源
# 若不配置,则默认不启动 prediction
prediction:
predictionWindowSeconds: 3600 # PredictionWindowSeconds 是预测未来指标的时间窗口。
predictionAlgorithm:
algorithmType: dsp
dsp:
sampleInterval: "60s"
historyLength: "3d"
crons:
- name: "cron1"
description: "scale up"
start: "0 0 ? * 6"
end: "00 23 ? * 0"
targetReplicas: 100
当你查看 EffectiveHorizontalPodAutoscaler 的 Status 时,可以会看到这样的错误:
- lastTransitionTime: "2022-05-15T14:05:43Z"
message: 'the HPA was unable to compute the replica count: unable to get metric
crane_pod_cpu_usage: unable to fetch metrics from custom metrics API: TimeSeriesPrediction
is not ready. '
reason: FailedGetPodsMetric
status: "False"
type: ScalingActive
原因:不是所有的工作负载的 CPU 使用率都是可预测的,当无法预测时就会显示以上错误。
解决方案:
DSP
需要一定时间的数据才能进行预测。希望了解算法细节的可以查看算法的文档。