HPA似乎很简单。我通过遵循所有的文档来启用它。但它对我不起作用!
这是真的,HPA(水平Pod自动定标器)不工作的某些应用或者是应用程序所有者做了什么错误的事情,破坏了HPA?继续往下读吧。
在继续讨论这些问题之前,让我们简要了解一下通常如何为应用程序配置HPA。
HPA基本功能
作为一个例子,让我们考虑一个服务busybox-1
。目标是让这个服务在CPU使用率超过80%时自动伸缩。
由于目前Pod垂直伸缩受到各种硬件资源的限制,我们使用HPA实现自动定标。
下面是HPA资源的示例清单。
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: busybox-1
spec:
scaleTargetRef:
kind: Deployment
name: busybox-1
minReplicas: 3
maxReplicas: 4
targetCPUUtilizationPercentage: 80
注意:虽然本文将以基于CPU利用率的水平Pod自动伸缩为例,但这些概念同样适用于任何可用于自动伸缩的指标。
使用此HPA资源配置busybox-1
部署非常简单,只需运行以下命令。
$ kubectl create -f hpa.yaml
horizontalpodautoscaler.autoscaling/busybox-1 created
如下图所示,可以查看HPA资源的当前状态。
$ kubectl get hpa
NAME REFERENCE TARGET MINPODS MAXPODS REPLICAS AGE
busybox-1 Deployment/busybox 0% / 80% 3 4 1 11m
当所有pod的平均CPU使用率超过80% (targetcpuutilationpercentage)时,HPA将启动其他pod。以下所示计算了额外需要Pod的数量。
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
在任何时间点应该运行的最小副本数量由minReplicas参数控制,HPA可将部署扩展到的最大副本数量,这由HPA清单中的maxReplicas参数控制。
我敢肯定,所有这些看起来都很简单,以至于你现在想知道HPA可能出了什么问题而无法工作。好吧,继续读下去!
目标资源利用率
下图考虑了具有稳定工作负载的服务示例。图中有三幅图。从上到下排列,它们描述如下:
根据所有pod的总CPU使用情况,在服务上加压。CPU总使用量是指处理服务上累积工作负载所需的CPU容量。例如,总CPU使用量为240%表明该服务至少需要240%÷100% = 2.4 pods来处理工作负载。
100%为1个pod的容量
所有pod的平均CPU使用率% (= CPU总使用率% ÷ pod数量)
在任何给定时间点运行Pod的数量
![](https://i-blog.csdnimg.cn/blog_migrate/7be154a440a88f853044045751d629e8.png)
服务被配置为随HPA自动伸缩。从上图的右上角可以看到,它被配置为以80%的期望CPU使用率运行,minReplicas参数设置为1。
记住这些要点之后,让我们看看在上面的例子中随着时间的推移发生了什么。
该服务的工作量从上午9点左右稳步增加,直到中午之后达到峰值。然后,在一天快结束的时候,它会逐渐变小
直到第一条下降线(黑色垂直虚线向下延伸到蓝色垂直虚线),处理工作负载所需的总CPU小于80% (< targetcpuutiliationpercentage)。因此,HPA不扩展,Pod的数量为1
超过这一点,处理工作负载所需的总CPU使用量将增加80%以上
HPA扩大部署,增加一个副本,因此运行的pod总数= 2
现在,有两个pod在运行,累积CPU负载为~85%,所有pod的平均CPU使用量为~ 43%
所有这些都是预期行为。HPA通过添加更多副本来响应工作负载的增加,并设法将平均CPU利用率保持在配置的~ targetcpuutilationpercentage
问题
让我们关注图中我们还没有描述的一些东西——蓝色的垂直线和橙色的垂直线。
蓝色虚线是突破80%阈值的时间标记
橙色虚线是一个时间标记,在这个时间段额外扩展的Pod已经运行
在检测和缩放之间有一个时间延迟
从图中可以看出,这两者之间存在时间差(即,在超出目标CPU使用率阈值和额外副本启动并运行之间存在时间差。
延迟的原因将在本文后面描述
自动缩放延迟=从超出目标CPU使用率阈值到额外副本启动并运行之间的时间间隔
现在让我们关注红色虚线。这是一个标记,表示如果服务没有扩展,pod将达到100% CPU利用率的时间。我们假设您不希望pod的CPU使用率达到这个级别,因为您在这个级别上观察到大量的节流—这会导致严重的降级和故障。
autoscale可用的最大时间=超出目标CPU利用率阈值和pod达到100% CPU利用率之间的时间滞后.
为了使自动缩放解决方案有效,一个关键的要求是让自动缩放延迟<自动缩放可用的最大时间
解决方案
减少自动扩展延迟超过最大可用时间的风险的一种方法是减少targetcpuutilationpercentage参数的值。
例如,在上面的场景中,如果targetcpuutilationpercentage设置为40%(而不是80%),那么阈值将会提前突破,并且需要3倍的时间才能达到100%的CPU利用率。因此,这种方法大大降低了降级/失效的风险。
但是,这里有一个权衡:目标CPU利用率越低,处理相同工作负载所需的pod数量就越多(在上面的示例中为240%)。下表说明了这种权衡和相关成本。
![](https://i-blog.csdnimg.cn/blog_migrate/b09d8083dfd908e675b3f3fb66edebcd.png)
处理40%目标CPU利用率的给定工作负载所需的pod数量是处理80%目标CPU利用率的相同工作负载所需的pod数量的两倍。
正如本节所解释的,目标利用率的选择在开始时可能看起来很简单,但应用程序所有者在对这个关键参数做出决策时,最好注意涉及的权衡。
更高的目标CPU利用率=更高的降级/故障风险 较低的目标CPU利用率=更昂贵的硬件资源
服务有损探测
现在,让我们考虑一个具有尖峰工作负载的服务示例。下图包含2个图表。从上到下排列,它们描述如下:
出现资源占用峰值
大量运行的Pod
服务被配置为随HPA自动伸缩。从上图的右上角可以看到,它被配置为以80%的期望CPU使用率运行,minReplicas参数设置为1。
记住这些要点之后,让我们看看这个例子中随着时间的推移会发生什么。
工作负载在一段时间内保持较低的水平,CPU使用率< 20%
然后突然出现高峰,CPU使用率>在短短几秒内达到80%
预期是,当CPU使用率超过80%时,HPA应该启动一个新的pod来处理增加的工作负载
但是,从上图中可以看出,HPA在这里并没有这样做
HPA有时无法检测工作负载峰值
是什么导致了这种行为?
为了理解这种行为的根本原因,让我们看一下下面演示的示例Kubernetes集群。
![](https://i-blog.csdnimg.cn/blog_migrate/345e8032ea90494dee164f5df66a2b1b.png)
下面解释了上述插图中的各种步骤。
当指标出现峰值时,HPA不会接收事件。相反,HPA每隔几秒从度量服务器轮询一次度量(可通过——horizontal-pod-autoscaler-sync-period标志进行配置,在本例中为15秒)
度量服务器(默认情况下HPA轮询度量)本身在一段时间内轮询聚合度量,每几秒轮询一次(可通过——度量分辨率标志进行配置,在本例中为30秒)
在本例中,将HPA配置为基于targetaveragecpu利用率度量进行伸缩。在这个度量中,有两个关键字值得注意:平均和利用率。
让我们来看看一些峰值的例子,以及在这些峰值期间HPA观察到了什么。
例1
![](https://i-blog.csdnimg.cn/blog_migrate/5bd589013f87001cc4fe88fba08a1788.png)
上面的示例显示了一个服务的3个pod在30秒内的CPU使用情况(metrics-server解析)。其中一个pod在T+1时出现CPU峰值,将该pod的CPU使用率推高至90%。这是在HPA中配置的> 80% targetAverageCPUUtilization参数。然而,在这个工作负载高峰期间,HPA不会向pod扩展,因为:
尽管其中一个pod的CPU峰值>为80%,但在T+1时,所有pod的平均CPU利用率仅为43%
此外,metrics服务器在一段时间内(本例中为30秒)提供聚合指标,在这30秒间隔内的聚合平均CPU利用率为21%——远低于80%的目标
由于这些原因,即使在一个pod中出现了工作负载峰值,导致该pod上的> CPU使用量达到80%,HPA也不会通过扩展更多副本来做出响应。
例2
在本例中,所有pod在T+1时经历了CPU峰值>80%。然而,在30秒的时间内,CPU平均使用量的总和只有22%——再次远低于80%的目标。因此,HPA不会通过扩展更多的副本来响应。
例3
在本例中,工作负载峰值持续的时间更长,约为5秒。然而,平均CPU利用率聚合超过30秒= 31% < 80% targetaveragecpu利用率。因此,HPA同样不能向外扩展部署。
例4
最后,在本例中,所有pod的平均CPU使用率在30秒(~ 26秒)的大部分时间内始终高于targetAverageCPUUtilization值。这将导致总平均CPU使用率= 81% > 80% targetaveragecpu利用率。因此,HPA通过添加额外的副本来扩展部署。
总结无损检测的主要发现。
因为HPA依赖于来自度量服务器的聚合度量,所以简短的工作负载峰值(以秒为单位)可能不足以将聚合值移动到HPA目标上
除了以上原因,在本例中,触发器是平均CPU利用率(它本身是在一个间隔内平均的),所以从HPA的角度来看,每秒发生的短暂峰值也可能丢失(如果平均间隔>>峰值周期)
HPA可能不是检测短暂/短期内产生工作负载峰值的最佳解决方案
解决方案
在这种工作负载下实现HPA规模的可能解决方案包括:
增加度量分辨率——如果您使用metrics-server来获取度量,这可能很简单,只需将- metric-resolution标志配置为低于上述示例中提到的30秒的值。
注意:指标的分辨率越高,集群上的开销就越大。因此,在无损检测和集群开销/可靠性之间需要进行权衡。
权衡:无损检测vs集群开销/可靠性
另外,对于期望这样的工作负载(即)的pods使用一个突发QoS。在上面描述的示例中,将limits参数的值设置为>requests参数值的4倍。因此,如果在正常情况下pod只需要2个CPU核,则requests参数可以设置为2,limits参数可以设置为8(或更多)。在正常情况下,只使用2个核,但是如果有一个工作负载峰值,pod将被允许使用超过请求的2个核,直到配置的限制值,在本例中为8(或更多)。这种方法不使用HPA进行可伸缩性,而是使用灵活的容器资源配置来处理可伸缩性。
注意:Burstable QoS不保证可伸缩性(即)更多的资源分配给pod,只有在可用的情况下。如果调度pod的节点100%繁忙,则pod无法获得额外资源。此外,与有保证QoS的pod相比,在资源压力情况下,具有突发QoS的pod更有可能(并非总是)被驱逐。因此,这里的权衡是无损检测和可伸缩性保证+可用性之间的权衡。
权衡:无损检测vs可伸缩性保证+可用性
响应能力
让我们考虑一下在本文的目标利用率一节中前面描述的稳定工作负载的例子。
在该部分中,我们讨论了检测(蓝色虚线)和缩放(橙色虚线)之间的时间延迟,以及如何通过调整targetAverageCPUUtilization参数来管理这种延迟(尽管有一定的成本)。
这一节中,我们将深入研究这种延迟的根本原因,并探讨减少这种延迟的可能方法。
![](https://i-blog.csdnimg.cn/blog_migrate/b2e66fb34c2570efaab810f08b407099.png)
如上所示,主要的贡献者与HPA的自动缩放延迟是:
HPA探测过程
应用程序启动过程
HPA探测过程
下面是本文前面讨论的Kubernetes集群示例。
![](https://i-blog.csdnimg.cn/blog_migrate/5a98311f1679e6b5a56384ead211b370.png)
正如前面所讨论的:
当指标出现峰值时,HPA不会接收事件。相反,HPA每隔几秒从度量服务器轮询一次度量(可通过- horizontal-pod-autoscaler-sync-period标志进行配置,在本例中为15秒)
度量服务器(默认情况下HPA轮询度量)本身在一段时间内轮询聚合度量,每几秒轮询一次(可通过度量分辨率标志进行配置,在本例中为30秒)
在本例中,根据HPA轮询的时间,可能会有30 - 45秒的延迟(30秒度量服务器解析+ 15秒HPA轮询频率)。
这是导致自动缩放延迟的原因之一。
应用程序启动过程
另一个可能是更重要的自动缩放延迟的组成部分是应用程序启动。在高水平上,用HPA自动缩放将经过3个步骤
检测-HPA检测到超过目标阈值
扩容-通过HPA发出扩容请求作出回应
容器就绪-新的副本开始接收流量
虽然这个过程的第3步——容器准备就绪——不是由HPA负责的,但它是自动缩放产生任何影响的关键。如果一个新的副本不能从流量中分得一杯羹,那么扩展它还有什么意义呢?
当HPA发出一个scale请求时,Kubernetes控制平面将新的pod调度到一个适当的工作节点上运行。但是,在调度程序调度pod和pod实际开始使用流量之间有一个时间差。这种延迟是由以下原因引起的:
镜像下载——要启动pod,与pod相关的容器图像需要在工作节点上可用。如果没有,则需要从存储库下载这些镜像。这可能需要一些时间,特别是如果容器镜像很大(几个MB或更多)。
初始化过程——许多应用程序在启动时依赖于初始化过程来加载配置、预热应用程序等等,这些过程花费的时间越长,pod移动到就绪状态所需的时间就越长。
准备检查——最后,除非通过准备检查,否则Pod不会被标记为就绪状态。除非它们被标记好,否则不能通行!对于应用程序所有者来说,指定一个大的initialDelaySeconds(活跃探测或准备探测启动前容器启动后的秒数)并不罕见,因为完成初始化过程所花费的时间是不确定的。在这种情况下,即使容器准备好了,准备状态检查可能也不会执行,直到较大的initialDelaySeconds时间过去。这将导致新的pod接收流量的进一步延迟。
解决方案
帮助autoscaler更快的可能解决方案:
保持容器镜像较小。镜像越小,从远程仓库下载的速度就越快
保持短时间内完成初始化过程-避免在启动时加载大的配置;试着保持快速的热加载。对于某些应用程序,较短的初始化时间可能意味着对运行时性能的妥协。要注意这种权衡。
权衡:启动性能vs运行时性能
保持就绪检查之间的延迟(包括初始延迟)合理。长时间的延迟可能会导致这样一种情况:容器已经准备好了,但检查正在等待延迟失效,然后再运行检查。这里的挑战是估计初始化过程的持续时间。可能很难准确地估计,但是对于自动缩放的目的来说,合理的近似比随机延迟要好得多
最后,增加度量解析或增加HPA轮询频率。这可能与将——metric-resolution标志(metrics-server)和——horizontal-pod-autoscaler-sync-period (HPA)配置为一个更低的值一样简单。采集指标的分辨率/轮询频率越高,集群的开销就越大。因此,在响应性和集群开销/可靠性之间需要权衡。
权衡:响应性vs集群开销和可靠性
弹性
HPA对于处理存在波动的应用程序无疑是有用的。但是,有时,在试图管理它们的容量时,HPA可以自动扩展应用程序,以至于一个应用程序可以占用Kubernetes集群中的所有资源,而留给在集群上运行的其他应用程序的资源非常少---如下图所示,其中应用程序1占用了所有资源。
您可能想知道——应用程序能够根据工作负载进行伸缩,这不是一件好事吗?如果集群的资源压力过大,可以不使用集群自动扩展器来处理这个问题吗?!
无限制的扩展可能会损害集群中应用程序的性能/可靠性
这确实有些道理,而且肯定是一个可行的解决方案。但想象一下,如果其中一个应用程序受到机器人流量的狂轰轰炸,其工作负载将是正常工作负载的100倍。在这种情况下,HPA可能会将应用程序扩展100倍。这有以下副作用:
硬件资源很贵,比平时贵100倍
所有这些钱都花在了机器人流量上,并没有增加任何商业价值
它将集群置于胁迫之下。尽管集群自动scaler将帮助缓解一些压力,但事实上,集群自动scaler也需要时间来检测和响应(延迟),而且大多数基础设施在可旋转的节点数量上配置了限制,可能无法完全避免对集群和在集群中运行其他应用程序的压力
解决方案
消除这种情况的一种方法是将HPA限制为最大的副本数量,防止无限制的缩放。您可以使用HPA清单中的maxReplicas参数对此进行配置。
在下面的示例清单中,HPA被限制为最多4个副本。
对于大多数应用程序,工作负载是可预测的。因此,为maxReplicas参数提供一个值并不太难。但是,当工作量无法预测时,你该怎么办?
例如,假设你经营一个新闻网站。对新闻的需求会随着新闻的趋势而上下波动。如何预测系统上的最大预期负载?!
准确预测最大预期工作量可能是不可能的。但是,一个基于事实的、合理的近似估计要比一个随机的估计好得多。例如:在新闻网站示例中,您可以使用以下指标得出一个估计。
随着时间的推移,基本用户的数量(N)——定期访问网站的用户
工作负载(W) -请求/秒-超时时间
每个副本的容量(C)——以请求数/秒为单位
下图显示了30天内的这些指标。
从这里可以看出,30天内使用的Pod最多是7个。因此,当选择maxReplicas参数时,明智的做法是添加一个缓冲区,但要确保这是合理的(即),在这种情况下,将maxReplicas参数设置为10比将其设置为100更好。
这里的权衡是弹性和无限扩展。在上面的例子中,如果有一条突发新闻完全抛弃了任何过去的数字,导致100倍的正常工作负载,HPA将无法处理这一情况。
权衡:弹性vs无限扩展
总结
提出了一套自动扩展解决方案的接受标准——可靠性、效率、响应性和弹性
应用程序所有者面临的挑战是,其中每一个都涉及到权衡和决策。
有时,帮助改善一项标准的尝试可能会损害另一项标准。
应用程序所有者需要注意:启用HPA与拥有一个正常工作的自动缩放解决方案是有差距的。
对应用程序所有者的建议是理解权衡、收集指标并做出明智的决定,以改进基于HPA的自动伸缩解决方案,使其适用于您的应用程序。
推荐
从Ice到Kubernetes容器技术,微服务架构经历了什么?
随手关注或者”在看“,诚挚感谢!