浅谈弹性伸缩应用

什么是弹性伸缩

弹性伸缩(Auto Scaling)是根据业务需求和策略自动调整计算能力(即实例数量)的服务。在业务需求增长时,弹性伸缩自动增加指定类型的实例,来保证计算能力;在业务需求下降时,弹性伸缩自动减少指定类型的实例,来节约成本。
简而言之,就是当需要很多机器的时候自动扩充机器的数量,当不需要那么多机器了,就自动缩减机器的数量。

使用场景

那么弹性伸缩技术有什么用途吗?
比如在正常情况下50个实例就够使用了,当出现某个热点事件时,服务请求量突增,这时候需要100个实例,就需要临时扩充实例数,但当热点过去时,请求量下降,需要再恢复至50个实例。这个过程就涉及到实例的扩缩。
当然,完全可以通过手动执行水平扩缩容来达到目的,但对于业务量存在不断波动的场景手动调整过于麻烦也容易出现调整不及时的情况,而且对于无法预料的流量突增情况如果未能及时调整实例数量,就会造成服务瘫痪,甚至引发雪崩。

设计一套智能扩缩容的机制

下面考虑对于新部署的服务如何一步步去优化扩缩容的机制

手动调整实例数目

我们新创建了一个服务,并为这个服务创建了集群,指定了部署实例数为50台,每台实例上都运行着相同的代码。但由于周末的时候流量会有一个突增,每周五晚九点将实例数手动调整为60台,然后周一早上再将实例数调整为50台。

定时任务

每周都需要进行如此重复的操作,作为研发人员显然是忍受不了的,于是考虑通过定时任务来完成这种周期性的调度过程。于是我们在服务中提供一个调度服务实例的接口,实现增加和减少实例数的功能,在ticker上进行定时调度,每周五晚上通过调度该接口增加实例数,每周一早上调用该接口减少实例数。

taskA:
接口:AdjustPodsCount
调度时间:每天定时调度
功能:周五增加10台机器,周一减少10台机器

配置监控规则

建立了定时任务之后发现再也不用每周手动调整实例数了,但预期外的流量突增情况仍无法解决,比如有突然的热点事件导致服务访问量大幅增加,但定时调度实例的方案无法满足这种情况。当发现服务异常时由于处理较晚造成了较大的损失,于是考虑配置更加精细化的监控规则。
这里主要考虑两个方面的指标,机器的硬件指标以及业务上定义的指标,于是在定时任务中加入机器cpu利用率以及服务qps的监控。
对原定时任务功能进行扩充

taskA:
接口:AdjustPodsCount
调度时间:每天定时调度
功能:根据规则调整实例数
规则:
    触发条件一:周五晚上
    行为:增加10台机器
    触发条件二:周一早上
    行为:减少10台机器
    触发条件三:qps > 1000
    行为:增加5台机器
    触发条件一:qps < 1000
    行为:减少5台机器

拆分扩缩容模块

目前我们的定时任务已经可以支持基本的使用场景了,后续有其他规则也可以增加进来进一步完善规则。但随着规则配置的增加,该任务越来越复杂,而且不能被其他服务复用。
于是我们考虑将这个任务拆分出来作为一个独立的服务,统一管理扩缩容的配置与底层调度。这样就将扩缩容模块与原服务解耦,将原任务拆分成一个个独立的扩缩容任务分别与不同服务绑定。

taskA:
接口:AddPodsCountOnTime
调度时间:每天定时调度
功能:增加10台机器
触发条件:周五晚上
绑定服务:服务A

taskB:
接口:ReducePodsCountOnTime
调度时间:每天定时调度
功能:减少10台机器
触发条件:周一早上
绑定服务:服务A

taskC:
接口:AddPodsCountByQPS
调度时间:每天定时调度
功能:增加5台机器
触发条件:qps > 1000
绑定服务:服务A

taskD:
接口:ReducePodsCountByQPS
调度时间:每天定时调度
功能:减少5台机器
触发条件:qps < 1000
绑定服务:服务A

建立伸缩组

目前虽然单独拆分出来了一个自动扩缩容服务,但依然存在一些问题,如果某个服务只有10个实例,触发缩容时导致实例数为0,这就导致服务不可用了,且自动扩缩容的实例与原有实例的规格是一致的且无法区分。
既然拆分成了一个单独服务,我们就考虑将自动扩缩的实例统一管理,于是定义一个伸缩组的概念,同一伸缩组下的实例规格可以自定义且保持一致,所有的扩缩容操作均在伸缩组内进行,不影响原机器。于是任务可以进行如下配置:

taskA:
接口:AddPodsCountOnTime
调度时间:每天定时调度
功能:增加10台机器
触发条件:周五晚上
绑定服务:服务A
绑定伸缩组:伸缩组A

伸缩组A:
机器规格:2C4G
最大实例数:50
最小实例数:5

定义了伸缩组的概念就可以方便做一些其他的操作,比如配置允许的最大和最小实例数,为伸缩组配置监控规则进行监控。

扩缩容策略

上述规则中所实现的实际功能都是对机器的简单调度,但随着服务发展,调度的规则也可能变的越来越复杂,且多种多样。比如是将机器数直接扩充至某一数目,按照步长设置动态扩缩容,或者设置指标阈值的波动范围,根据超出阈值的程度动态调整机器数。
此时,可以将触发的动作抽象成具体的策略,与不同的规则绑定。每个规则执行绑定的策略。

taskA:
接口:AddPodsCountOnTime
调度时间:每天定时调度
功能:增加10台机器
触发条件:周五晚上
绑定服务:服务A
绑定伸缩组:伸缩组A
绑定策略:策略A

策略A:
策略类型:按步长动态增加实例数
步长:2
回避时长:300s

如上所示,每次以固定步长扩充实例,同时设置回避时长防止频繁变更造成的服务不稳定。

使自动扩缩容更加智能化

目前的自动扩缩容功能已经比较完备了,我们可以想办法使其更加智能化。

目标自适应

上述的自动扩缩容功能只能调整固定的实例数,在实际使用起来需要用户手动计算需要扩缩多少实例。很多时候的需求可能是将cpu使用率维持在一个固定值附近,比如将cpu使用率维持在15%,这样只需要提供目标,服务根据目标及原服务的实例规格及使用率自动采取最适合的策略,实现服务的cpu使用率维持在目标值附近。
这里在实际规则及策略的制定上对用户保持了透明,完全由平台提供方自定义算法策略。

预测智能化

上述能力主要是节省了策略制定的过程,那么智能化预测主要是节省规则上的制定。根据服务相关指标的历史数据,通过采用机器学习的方式了解历史流量的变化规律,什么时候处于峰值,什么时候处于低谷,自动配置合适的规则和策略。
另外一个方向是后置预测,即根据流量变化自动调整机器扩缩的数量。当流量突增较大时增加更多的实例以很好的应对流量峰值。

原理

弹性伸缩没有什么复杂的原理,更多的是一种设计思想,如何更加智能化的解决资源扩缩容的问题,所以本文从如何设计一套自动扩缩容系统一步步抽象优化。在设计上主要包含三个方面

一、指标

因为弹性伸缩主要是根据某些指标达到设定的阈值了,然后触发什么什么操作。所以指标获取是第一步,比如 CPU 负载、内存使用率等系统指标,以及 QPS 等业务指标,无论哪种指标,一定是有另外一个统一的打点监控平台去收集的,只需要调他们接口获取就好了,就是一个数值的获取。

二、指标聚合

即根据设定的目标以及获取的指标计算出不同规则算法下机器扩缩的数目,对于多个规则的方案进行聚合得出最终实际需要扩缩的机器数目

三、机器调度

第三步则是在得出聚合目标之后,根据一定的策略机器。底层实际上就是 k8s 调度 docker 容器那一套了,对于弹性计算产品来说,也是调几个接口的事情,无需关心底层具体调度逻辑。

弹性伸缩的具体应用

Kubernetes中pod水平自动缩放

HorizontalPodAutoscaler 会自动更新工作负载资源,目的是自动扩展工作负载以满足需求。
Kubernetes的水平扩缩容会调整部署的pods,当负载增加或减少时对应的增加或减少pod的数量。
HorizontalPodAutoscaler基于资源以及控制器实现,资源决定了控制器的行为,控制器通过开发api及接口部署并管理容器的生命周期。目的是通过调整所需规模匹配目标指标,可以是平均cpu利用率或者平均内存利用率,也可以是任何其他的自定义指标。

HorizontalPodAutoscaler工作原理

在这里插入图片描述
HorizontalPodAutoscaler控制着部署的容器规模,通过一个间歇性运行的循环控制算法,定期检查标记pod的指定指标,根据获取到的指标值以及目标值计算出扩缩容的比例。
算法流程如下:
在这里插入图片描述
扩缩容比例的计算是根据指标的目标值以及当前值所确定,计算公式如下:
desiredReplicas = ceil[currentReplicas * (currentMetricValue / desiredMetricValue )]
比如当前指标值是200,目标指标值是100,当前pod数是50,则目标pod数是100,需要扩容一倍,若当前指标值是50,则需要缩减一倍。但对于缩放有一个误差容忍度,当currentMetricValue / desiredMetricValue比率在容忍度范围内时跳过本次扩缩容,HorizontalPodAutoscaler设置的默认值是0.1。
对于如上指标的计算,HorizontalPodAutoscaler是采用一种比较保守的方式。在计算比率之前,会先对pod进行检查,如果存在计算指标缺失、未就绪或处于删除状态的容器,则将该容器置为预留态,如果容器部署失败则将其置为丢弃状态。
在进行pod的标记之后,采用所有未置为预留或丢弃状态的pod参与计算,同时根据这两种特殊状态的pods对计算结果进行进一步的矫正。
而HorizontalPodAutoscaler采用的是一种保守的矫正策略,对于需要缩减的情况将特殊状态的容器对目标指标的贡献值视为100%,而对于需要扩充容器的情况将贡献值视为0%。实际就是对缩减进行限制,对扩充进行放开。
当有多个指标参与计算时,取所有期望值中的最大值作为最终的desiredReplicas。同样的,对于某个指标获取失败的情况,保持保守计算的策略,若其他所有指标计算值都是缩减则忽略此次扩缩,反之只要存在一个扩充的情况则进行扩容。
在缩减时为防止指标波动过大,支持步进式的容器缩减,默认时间间隔为5分钟。

Kubernetes稳定性保证

thrashing / flapping: 由于参与评估的指标是动态变动的,因此会造成pod数量的波动,因此Kubernetes对于部署规模上进行了一系列的稳定性保证

  • 滚动更新
    Kubernetes允许对部署执行滚动式更新,在这种情况下,Deployment 会管理底层的 ReplicaSet。为 Deployment 配置自动缩放时,会将 HorizontalPodAutoscaler 绑定到单个 Deployment,并保证滚动更新的总数目与目标数目一致。
  • 支持资源指标
    任何 HPA 目标都可以根据扩展目标中 pod 的资源使用情况进行扩展。在定义 pod 规范时,应指定类似于cpu或memory的资源请求。这用于确定资源利用率,并由 HPA 控制器用于向上或向下扩展目标。要使用基于资源利用率的缩放,需要指定一个指标源:
type: Resource
resource:
  name: cpu
  target:
    type: Utilization
    averageUtilization: 60

如上所示可以保证缩放目标pod的总cpu利用率在60%,同时也支持容器级别的控制:

type: ContainerResource
containerResource:
  name: cpu
  container: application
  target:
    type: Utilization
    averageUtilization: 60
  • 缩放行为可配置
    通过behavior字段来控制单独的缩减或扩充行为

    • 通过扩展策略控制副本的变化率,可支持配置多个策略
      periodSeconds表示策略必须成立的过去时间长度。第一个策略(Pods)允许在一分钟内最多缩小 4 个副本。第二个策略 (百分比)允许在一分钟内缩小当前副本的最多 10%。
    behavior:
      scaleDown:
        policies:
        - type: Pods
          value: 4
          periodSeconds: 60
        - type: Percent
          value: 10
          periodSeconds: 60
    
    • 可以通过指定selectPolicy缩放方向的字段来更改策略选择。通过将值设置为Min选择允许副本计数最小变化的策略的值。将该值设置为Disabled完全禁用该方向的缩放。
    behavior:
     scaleDown:
       policies:
       - type: Percent
         value: 10
         periodSeconds: 60
       - type: Pods
         value: 5
         periodSeconds: 60
       selectPolicy: Min
    
    • 当用于扩展的指标不断波动时,稳定窗口用于限制副本数目计算的波动。自动缩放算法使用此窗口来推断先前的期望状态并避免对工作负载规模进行不必要的更改。
      例如,在以下示例代码段中,为 指定了稳定窗口scaleDown。
      当指标表明目标应该按比例缩小时,算法会查看先前计算的所需状态,并使用指定间隔中的最大值。在上面的示例中,将考虑过去 5 分钟的所有所需状态。如果5分钟内的最大值在可容忍范围内则不会进行缩放,这就使得资源利用率持续一个窗口的时间均低于阈值才会触发缩放。
    behavior:
      scaleDown:
        stabilizationWindowSeconds: 300
    

参考

  • https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
  • https://blog.csdn.net/gaofei0428/article/details/121306924?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-121306924-blog-124977131.pc_relevant_multi_platform_featuressortv2dupreplace&spm=1001.2101.3001.4242.1&utm_relevant_index=3
  • https://help.aliyun.com/product/25855.html
  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值