腾讯自研业务上云:优化Kubernetes集群负载的技术方案探讨

Author: xidianwangtao@gmail.comnode

摘要:Kubernetes的资源编排调度使用的是静态调度,将Pod Request Resource与Node Allocatable Resource进行比较来决定Node是否有足够资源容纳该Pod。静态调度带来的问题是,集群资源很快被业务容器分配完,可是集群的总体负载很是低,各个节点的负载也不均衡。本文将介绍优化Kubernetes集群负载的多种技术方案。web

Kubernetes为何使用静态调度

静态调度,是指根据容器请求的资源进行装箱调度,而不考虑节点的实际负载。静态调度最大的优势就是调度简单高效、集群资源管理方便,最大的缺点也很明显,就是无论节点实际负载,极容易致使集群负载不高。后端

Kubernetes为何会使用静态调度呢?由于要作好通用的动态调度几乎是不可能的,对,是通用的动态调度很难都知足不一样企业不一样业务的诉求,结果可能拔苗助长。那是否是咱们就不必去往动态调度作技术尝试呢?未必!平台根据托管的业务属性,能够适当的经过scheduler extender的方式扩展Kubernetes Scheduler来作必定权重的动态调度决策。api

集群资源构成

以cpu资源为例,一个大规模Kubernetes集群的资源组成结构大体以下:性能

由如下几部分组成:优化

  • 每一个节点的预留资源,对应kubelet的system-reserved, kube-reserved, eviction-hard配置的资源之和,Kubernetes计算Node的Allocatable资源时会减去这部分预留资源。
  • 目前咱们集群的平均资源碎片大概在5%~10%左右,根据不一样规格的CVM机型略有不一样。这些资源碎片分散在集群中的各个节点,以1c1g, 2c2g, 3cxg为主,平台提供用户选择的容器规格都很难match到这些碎片,常常存在这这种状况:要调度某个Pod时,发现某个节点上的cpu足够,可是mem不足,或者相反。
  • 剩下的就是能够被业务Pod真正分配使用的资源了,业务在选择容器规格时带有必定的主观性和盲目性,致使业务容器的负载很低,这样的业务占比一大就容易致使集群低负载的状况,可是集群按照Kubernetes静态调度策略又没法再容纳更多的业务容器了。如上图中所示的,集群分配cpu水位线很高,可是实际cpu利用率不高的状况。

提高集群负载的方案

除了借助强大的容器监控数据作必定权重的动态调度决策以外,是否还有其余方案能够用于解决静态调度带来的集群低负载问题呢?下面我将给出一整套技术方案,从多个技术维度来尝试提高Kubernetes集群负载。ui

Pod分配资源压缩

前面提到,研发同窗部署业务选择容器资源规格时,带有必定的盲目性,并且Kubernetes原生也不支持实时无感知的修改容器规格(虽然这能够经过Static VPA方案解决),致使业务容器负载低。为了解决这个问题,咱们能够给Pod Request Resource作必定比例的压缩(Pod Limit Resource不压缩)。注意压缩Pod Request Resource只发生在Pod建立或者重建的时候,好比业务作变动发布之时,对于正常运行中的Pod不能作这一动做,不然可能致使对应Workload Controller重建Pod(取决于Workload的UpdateStrategy)对业务带来影响。code

须要注意的是:orm

  • 每一个Workload负载变更规律不一样,所以Pod分配资源压缩比例也对应不同,须要支持每一个Workload自定义配置,并且这是对用户无感知的。这个压缩比,咱们设置到Workload的Annotation中,好比cpu资源压缩对应Annotation stke.platform/cpu-requests-ratioserver

  • 压缩比,谁去设置?自研组件(Pod-Resource-Compress-Ratio-Reconciler)基于Workload的历史监控数据,动态的/周期性去调整压缩比。好比某Workload连续7d/1M的负载持续很低,那么能够把压缩比设置的更大,以此让集群剩余可分配资源更大,容纳更多的业务容器。固然实际上压缩比的调整策略并不会这么简单,须要更多的监控数据来辅助。

  • Pod分配压缩特性必定要是能够关闭的和恢复的,经过Workload Annotation stke.platform/enable-resource-compress: "n"针对Workload级别disable,经过设置压缩比为1进行压缩恢复。

  • 什么时候经过压缩比去调整Pod Spec中的Request Resource?Kubernetes发展到现阶段,直接改Kubernetes代码是最愚蠢的方式,咱们要充分利用Kubernetes的扩展方式。这里,咱们经过kube-apiserver的Mutating Admission Webhook对Pod的Create事件进行拦截,自研webhook(pod-resource-compress-webhook)检查Pod Annotations中是否enable了压缩特性,而且配置了压缩比,若是配置了,则根据压缩比从新计算该Pod的Request Resource,Patch到APIServer。

Node资源超卖

Pod资源压缩方案,是针对每一个Workload级别的资源动态调整方案,优势是细化到每一个Workload,能作到有的放矢,缺点是业务不作变动发布,就没有效果,见效慢。

Node资源超卖方案是针对Node级别的资源动态调整方案,根据每一个节点的真实历史负载数据,进行不一样比例的资源超卖。

  • 每一个节点的资源超卖比例,咱们设置到Node的Annotation中,好比cpu超卖对应Annotation stke.platform/cpu-oversale-ratio

  • 每一个节点的超卖比例,谁去设置?自研组件(Node-Resource-Oversale-Ratio-Reconciler)基于节点历史监控数据,动态的/周期性的去调整超卖比例。好比某个Node连续7d/1M持续低负载而且节点已分配资源水位线很高了,那么能够把超卖比例适当调高,以此使Node能容纳更多的业务Pod。

  • Node超卖特性必定要是能够关闭和还原的,经过Node Annotation stke.platform/mutate: "false"关闭Node超卖,Node在下一个心跳会完成资源复原。

  • 什么时候经过压缩比去调整Node Status中的Allocatable&Capacity Resource?一样的,咱们经过kube-apiserver的Mutating Admission Webhook对Node的Create和Status Update事件进行拦截,自研webhook(node-resource-oversale-webhook)检查Node Annotations中是否enable了超卖而且配置了超卖比,若是配置了,则根据安超卖比从新计算该Node的Allocatable&Capacity Resource,Patch到APIServer。

Node资源超卖,表面上看起来很简单,但实际上要考虑的细节还不少:

  • Kubelet Register Node To ApiServer的详细原理是什么,经过webhook直接Patch Node Status是否可行?

  • 当节点资源超卖后,Kubernetes对应的Cgroup动态调整机制是否能继续正常工做?

  • Node status更新太频繁,每次status update都会触发webhook,大规模集群容易对apiserver形成性能问题,怎么解决?

  • 节点资源超卖对Kubelet Eviction的配置是否也有超配效果,仍是仍然按照实际Node配置和负载进行evict? 若是对Evict有影响,又该如解决?

  • 超卖比例从大往小调低时,存在节点上 Sum(pods' request resource) > node's allocatable状况出现,这里是否有风险,该如何处理?

  • 监控系统对Node的监控与Node Allocatable&Capacity Resource有关,超卖后,意味着监控系统对Node的监控再也不正确,须要作必定程度的修正,如何让监控系统也能动态的感知超卖比例进行数据和视图的修正?

  • Node Allocatable和Capacity分别该如何超卖?超卖对节点预留资源的影响是如何的?

这里涉及的Kubernetes技术细节比较多,我将在下一篇文章中详细介绍。

优化AutoScale能力

提起Kubernetes的弹性伸缩,你们比较熟悉的是HPA和HNA,一个对Workload的Pod进行横向伸缩,一个对集群中Node进行横向伸缩。社区中还有一个VPA项目,用来对Pod的资源进行调整,可是须要重建Pod才能生效,VPA存在的意义就是要快速扩容,若是像HPA同样,须要重建Pod启动应用来扩容,其实已经失去了价值。

Kube-controller-manager内置的HPA-Controller存在如下问题:

  • 性能问题:一个goroutine中循环遍历集群中全部的HPA对象,针对每一个HPA对象获取对应的Pod监控数据、计算新Replicas,这对于大业务是比较耗时的。

  • 核心配置不支持Workload自定义:HPA伸缩响应时间是每一个业务均可能不同的,有些业务指望能5s进行响应,有些业务以为60s就够了。而内置HPA Controller在响应时间控制上只能配置全局的启动参数horizontal-pod-autoscaler-sync-period。还有每一个业务对负载的抖动容忍是不同的,在内置的HPA Controller中只能经过horizontal-pod-autoscaler-tolerance作全局配置,没法提供业务级的自定义。

  • Kubernetes目前对custom metrics的支持,只能注册一个后端监控服务,若是集群中有些业务经过prometheus来expose应用自定义指标,也有一些业务经过Monitor来监控应用自定义指标,这个时候就作不到All in了,这在for自研上云的场景中,是必定存在的场景。

咱们自研了HPAPlus-Controller组件:

  • 每一个HPA对象会启动一个goroutine协程专门负责该HPA对象的管理和计算工做,各个协程并行执行,极大的优化了性能。HPAPlus-Controller独立部署,其资源需求能够是集群规模和HPA数量进行合理调整,相比于原内置HPA-Controller有更大的灵活性。

  • HPAPlus-Controller支持各个HPA对象自定义伸缩响应时间,支持自动感应业务是否在变动发布并决定是否要禁用HPA(某些业务有这样的需求:升级时禁止触发弹性伸缩),支持基于pod resource limit为基数进行Pod资源利用率计算,从而推导出扩缩容后的指望replicas,这一点对于节点超卖和Pod资源压缩后的集群很是重要。

  • 支持业务级别对负载的抖动容忍度的个性化配置。

  • 支持基于更多维度的监控数据进行Scale决策,好比Pod历史7d/1M的cpu负载。

  • 支持CronHPA,知足规律性扩缩容的业务诉求。

  • 经过Extension APIServer的方式对接公司Monitor监控,保留Prometheus-Adaptor的方式来支持基于Prometheus的应用监控,知足基于多种应用监控系统的custom metrics进行HPA。

注意:HPAPlus-Controller与Kubernetes buit-in HPA-Controller存在功能冲突,上线前须要disable kube-controller-manager的HPA-Controller控制器。

除了HPA的优化和加强以外,咱们也在进行Dynamic VPA技术研发,后续再单独文章介绍。

其余技术方案

另外,经过scheduler extender的方式开发动态调度器、基于业务级的配额动态管理组件、基于业务优先级和配额管理的在线离线业务混部能力、主动探测节点资源碎片信息并上报到控制器进行Pod的再漂移进行资源碎片管理等方案,也是咱们正在进行实践的方向,对应方案及实现复杂度更高,后续再单独文章介绍。

总结

本文介绍了Kubernetes静态调度带来的集群资源分配水位线高但集群实际负载低的问题进行了技术方案上的探讨,详细介绍了Pod资源动态压缩、节点资源动态超卖、优化AutoScale的能力的技术方案,后面会再对动态调度、动态业务配额管理、在线离线业务混部方案进行介绍。全部这些集群负载提高方案,要作到动态,都强依赖于强大的容器监控系统。咱们正与腾讯云监控产品团队深刻合做,更好的服务于腾讯自研业务上云。

相关文章
相关标签/搜索