Kubernetes弹性伸缩全场景解读(二) - HPA的原理与演进

前言

在上一篇文章中,我们介绍了在Kubernetes在处理弹性伸缩时的设计理念以及相关组件的布局,在今天这篇文章中,会为大家介绍在Kubernetes中弹性伸缩最常用的组件HPA(Horizontal Pod Autoscaler)。HPA是通过计算Pod的实际工作负载进行重新容量规划的组件,在资源池符合满足条件的前提下,HPA可以很好的实现弹性伸缩的模型。HPA到目前为止,已经演进了三个大的版本,在本文中会为大家详细解析HPA底层的原理以及在Kubernetes中弹性伸缩概念的演变历程。

HPA基本原理

HPA是根据实际工作负载水平伸缩容器数目的组件,从中可以提炼出两个非常重要的关键字:负载数目。我们可以用一个非常简单的数学公式进行归纳:

bacc0483353082a419e4d86a069b906a.png

下面举一个实际例子进行上述公式的阐述,假设存在一个叫ADeployment,包含3个Pod,每个副本的Request值是1核,当前3个Pod的CPU利用率分别是60%、70%与80%,此时我们设置HPA阈值为50%,最小副本为3,最大副本为10。接下来我们将上述的数据带入公式中。

  • 总的Pod的利用率是60%+70%+80% = 210%。
  • 当前的Target是3。
  • 算式的结果是70%,大于阈值的50%阈值,因此当前的Target数目过小,需要进行扩容。
  • 重新设置Target值为5,此时算式的结果为42%低于50%,判断还需要扩容两个容器。
  • 此时HPA设置Replicas为5,进行Pod的水平扩容。

经过上面的推演,可以协助开发者快速理解HPA最核心的原理,不过上面的推演结果和实际情况下是有所出入的,如果开发者进行试验的话,会发现Replicas最终的结果是6而不是5。这是由于HPA中一些细节的处理导致的,主要包含如下三个主要的方面:

  1. 噪声处理

通过上面的公式可以发现,Target的数目很大程度上会影响最终的结果,而在Kubernetes中,无论是变更或者升级,都更倾向于使用Recreate而不是Restart的方式进行处理。这就导致了在Deployment的生命周期中,可能会出现某一个时间,Target会由于计算了Starting或者Stopping的的Pod而变得很大。这就会给HPA的计算带来非常大的噪声,在HPA Controller的计算中,如果发现当前的对象存在Starting或者StoppingPod会直接跳过当前的计算周期,等待状态都变为Running再进行计算。

  1. 冷却周期

在弹性伸缩中,冷却周期是不能逃避的一个话题,很多时候我们期望快速弹出与快速回收,而另一方面,我们又不希望集群震荡,所以一个弹性伸缩活动冷却周期的具体数值是多少,一直被开发者所挑战。在HPA中,默认的扩容冷却周期是3分钟,缩容冷却周期是5分钟。

  1. 边界值计算

我们回到刚才的计算公式,第一次我们算出需要弹出的容器数目是5,此时扩容后整体的负载是42%,但是我们似乎忽略了一个问题,一个全新的Pod启动会不会自己就占用了部分资源?此外,8%的缓冲区是否就能够缓解整体的负载情况,要知道当一次弹性扩容完成后,下一次扩容要最少等待3分钟才可以继续扩容。为了解决这些问题,HPA引入了边界值△,目前在计算边界条件时,会自动加入10%的缓冲,这也是为什么在刚才的例子中最终的计算结果为6的原因。

HPA的演进历程

在了解了HPA的基本原理后,我们来聊一下HPA的演进历程,目前HPA已经支持了autoscaling/v1autoscaling/v1beta1autoscaling/v1beta2三个大版本。大部分的开发者目前比较熟悉的是autoscaling/v1的版本,这个版本的特点是只支持CPU一个指标的弹性伸缩,大致的yaml内容如下:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

接下来我们再来看一下v2beta1与v2beta2的yaml,会发现里面支持的metrics类型增加了很多,结构也复杂了很多。

apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        kind: AverageUtilization
        averageUtilization: 50
  - type: Pods
    pods:
      metric:
        name: packets-per-second
      targetAverageValue: 1k
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: extensions/v1beta1
        kind: Ingress
        name: main-route
      target:
        kind: Value
        value: 10k
---
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

而这些变化的产生不得不提的是Kubernetes社区中对监控与监控指标的认识与转变。在Kubernetes中,有两个核心的监控组件HeapsterMetrics Server。Heapster是早期Kubernetes社区中唯一的监控组件,它所包含的功能很强大,通过采集kubelet提供的metrics接口,并支持监控数据的离线与归档。
4831f8abbdaf67f45ac40f5d91fa5c5e.png

大致的架构图如下,source的部分是不同的数据来源,主要是kubelet的common api与后来提供的summary api;processor的作用是将采集的数据进行处理,分别在namespace级别、cluster级别进行聚合,并创建新的聚合类型的监控数据;sink的作用是数据离线与归档,常见的归档方式包括influxdb、kafka等等。Heapster组件在相当长时间成为了Kubernetes社区中监控数据的唯一来源,也因此有非常多的和监控相关的组件通过Heapster的链路进行监控数据的消费。但是后来,Kubernetes社区发现了Heapster存在非常严重的几个问题。

  • 强大繁多的Sink由不同的Maintainer进行维护,50%以上的Heapster Issues都是关于Sink无法使用的,而由于Maintainer的活跃度不同造成Heapster社区有大量的issues无法解决。
  • 对于开发者而言,监控数据的类型已经不再是CPU、Memory这么简单的几个指标项了,越来越多的开发者需要应用内或者接入层的监控指标,例如ingress的QPS、应用的在线活跃人数等等。而这些指标的获取是Heapster无法实现的。
  • Prometheus的成熟让Heapster的生存空间不断被挤压,自从Prometheus被CNCF收录为孵化项目,Heapster的不可替代地位被正式移除。

社区经过反思后,决定将监控的指标边界进行划分,分为Resource、Custom和External三种不同的Metrics,而Heapster(Metrics Server)的定位就只关心在了Resource这一种指标类型。为了解决代码维护性的问题,Metrics Server对Heapster进行了裁剪,裁剪后的架构如下:

99bf9ef330cace77238ede19f368f314.png

去掉了Sink的机制,并将调用方式改为标准的API注册的方式,这样的好处是既精简了核心代码的逻辑又提供了替代的可能,也就是说此时Metrics Server也是可以替代的,只要实现了相同的API接口,并注册到API Server上,就可以替代Metrics Server。

接下来我们解析一下三种不同的Metrics与使用的场景

API 注释
Resource metrics.k8s.io Pod的资源指标,计算的时要除以Pod数目再对比阈值进行判断
Custom custom.metrics.k8s.io Object: CRD等对象的监控指标,直接计算指标比对阈值
Pods : 每个Pod的自定义指标,计算时要除以Pods的数目
External external.metrics.k8s.io External:集群指标的监控指标,通常由云厂商实现

其中autoscaling/v2beta1支持Resource与Custom两种指标,而autoscaling/v2beta2中增加了External的指标的支持。

最后

HPA目前已经进入了GA阶段,在大体的功能上面不会进行过多的变化,目前社区的主要发力点在如何配置化的调整细节参数、丰富监控adapter的实现等等。在本文中,我们在概念上给大家介绍了HPA的一些原理以及发展的趋势,在下一篇文章中,我们会为大家讲解如何开启v2beta1v2beta2的。

猜你喜欢

转载自yq.aliyun.com/articles/673889