HPA 缩放即使当前 CPU 低于目标 CPU

HPA Scaling even though Current CPU is below Target CPU

我正在使用 Kubernetes 中的 Horizo​​ntal Pod Autoscaler。一旦平均 CPU 利用率超过 35%,我已将 HPA 设置为启动新实例。但是,这似乎没有按预期工作。 即使 CPU 利用率远低于定义的目标利用率,HPA 也会触发重新调整。如下所示,“当前”利用率为 10%,与 35% 相去甚远。但是,它仍然将 pods 的数量从 5 重新调整为 6。

我还检查了我的 Google 云平台仪表板(我们托管应用程序的地方)中的指标。这也表明请求的 CPU 利用率没有超过 35% 的阈值。但是,仍然发生了几次重新缩放。

我的 HPA 的内容

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
 name: django
spec:
{{ if eq .Values.env "prod" }}
 minReplicas: 5
 maxReplicas: 35
{{ else if eq .Values.env "staging" }}
 minReplicas: 1
 maxReplicas: 3
{{ end }}
 scaleTargetRef:
   apiVersion: apps/v1
   kind: Deployment
   name: django-app
 targetCPUUtilizationPercentage: 35

有人知道这可能是什么原因吗?

这很棘手,可能是一个错误,但我不这么认为,大多数时候人们配置的值太低,我将解释。

targetCPUUtilizationPercentage 如何与 Pod 的请求限制相关。

targetCPUUtilizationPercentage 根据 pod 可以使用的所有 CPU 配置一个百分比。在 Kubernetes 上,我们无法在不指定一些 limits 到 CPU 用法的情况下创建 HPA

假设这是我们的极限:

apiVersion: v1
kind: Pod
metadata:
  name: apache
spec:
  containers:
    - name: apache
      image: httpd:alpine
      resources:
        limits:
          cpu: 1000m

并且在我们的 targetCPUUtilizationPercentage 内部 HPA 中我们指定 75%。

这个很好解释,因为我们要求的是单核的100%(1000m = 1CPU核),所以当这个核是75%左右使用后,HPA 将开始工作。

但是如果我们这样定义我们的限制:

spec:
  containers:
    - name: apache
      image: httpd:alpine
      resources:
        limits:
          cpu: 500m

现在,我们的 pod 可以利用的 100% CPU 只有单个内核的 50%。很好,所以此 pod 的 cpu 使用率的 100% 意味着,在硬件上,单个内核的使用率为 50%。

这与 targetCPUUtilizationPercentage 无关,如果我们保持 75% 的值,HPA 将在我们的单核大约 37.5% 使用率时开始工作,因为这是 75%在所有 CPU 中,这个 pod 可以消耗。

从 pod/hpa 的角度来看,他们永远不知道自己在 CPU 或内存上受到限制。

理解上面问题中的场景

对于某些程序,例如上述问题中使用的程序 - 确实会出现 CPU 峰值 - 但是仅在较小的时间范围内 (例如10 秒峰值)。由于这些峰值的持续时间很短,指标服务器不会保存此峰值,而只会在 1m window 后保存指标。在这种情况下,windows 之间的尖峰将被排除在外。这解释了为什么指标仪表板中看不到尖峰,但被 HPA 拾取。

因此,对于具有 低 cpu 限制的服务, 更大的扩展时间 window scaleUp 设置在 HPA 中) 可以是理想的。

缩放基于 requests 而非 limits 的百分比。我认为我们应该更改此答案,因为已接受答案中的示例显示:

 limits:
   cpu: 1000m

但是 targetCPUUtilizationPercentage 是基于 requests 这样的:

requests:
   cpu: 1000m

For per-pod resource metrics (like CPU), the controller fetches the metrics from the resource metrics API for each Pod targeted by the HorizontalPodAutoscaler. Then, if a target utilization value is set, the controller calculates the utilization value as a percentage of the equivalent resource request on the containers in each Pod. If a target raw value is set, the raw metric values are used directly. The controller then takes the mean of the utilization or the raw value (depending on the type of target specified) across all targeted Pods, and produces a ratio used to scale the number of desired replicas.

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#how-does-a-horizontalpodautoscaler-work