超大规模商用 K8s 场景下,阿里巴巴如何动态解决容器资源的按需分配问题?

做者 | 张晓宇(衷源)  阿里云容器平台技术专家html

关注『阿里巴巴云原生』公众号,回复关键词“1010**”,可获取本文 PPT。**node

**导读:**资源利用率一直是不少平台管理和研发人员关心的话题。本文做者经过阿里巴巴容器平台团队在这一领域的工做实践,整理出了一套资源利用提高的方案,但愿可以带给你们带来一些讨论和思考。算法

引言

不知道你们有没有过这样的经历:当咱们拥有了一套 Kubernetes 集群,而后开始部署应用的时候,咱们应该给容器分配多少资源呢?数据库

这很难说。因为 Kubernetes 本身的机制,咱们能够理解容器的资源实质上是一个静态的配置。api

  • 若是我发现资源不足,为了分配给容器更多资源,咱们须要重建 Pod;
  • 若是分配冗余的资源,那么咱们的 worker node 节点彷佛又部署不了多少容器。

试问,咱们能作到容器资源的按需分配吗?接下来,咱们将在本次分享中和你们一块儿进行探讨这个问题的答案。安全

生产环境中的真实挑战

首先请容许咱们根据咱们的实际状况抛出咱们实际生产环境的挑战。或许你们还记得 2018 年的天猫双 11,这一天的总成交额达到了 2135 亿。由此一斑可窥全豹,可以支撑如此庞大规模的交易量背后的系统,其应用种类和数量应该是怎样的一种规模。微信

在这种规模下,咱们经常听到的容器调度,如:容器编排,负载均衡,集群扩缩容,集群升级,应用发布,应用灰度等等这些词,在被“超大规模集群”这个词修饰后,都再也不是件容易处理的事情。规模自己也就是咱们最大的挑战。如何运营和管理好这么一个庞大的系统,并遵循业界 dev-ops 宣传的那样效果,犹如让大象去跳舞。可是马老师曾说过,大象就该干大象该干的事情,为何要去跳舞呢。网络

Kubernetes 的帮助

大象是否能够跳舞,带着这个问题,咱们须要从淘宝、天猫等 APP 背后系统提及。架构

这套互联网系统应用部署大体可分为三个阶段,传统部署,虚拟机部署和容器部署。相比于传统部署,虚拟机部署有了更好的隔离性和安全性,可是在性能上不可避免的产生了大量损耗。而容器部署又在虚拟机部署实现隔离和安全的背景下,提出了更轻量化的解决方案。咱们的系统也是沿着这么一条主航道上运行的。假设底层系统比如一艘巨轮,面对巨量的集装箱---容器,咱们须要一个优秀的船长,对它们进行调度编排,让系统这艘大船能够避开层层险阻,操做难度下降,且具有更多灵活性,最终达成航行的目的。负载均衡

理想与现实

在开始之初,想到容器化和 Kubernetes 的各类美好场景,咱们理想中的容器编排效果应该是这样的:

  • 从容:咱们的工程师更加从容的面对复杂的挑战,再也不眉头紧锁而是更多笑容和自信;
  • 优雅:每一次线上变动操做均可以像品着红酒同样气定神闲,优雅地按下执行的回车键;
  • 有序:从开发到测试,再到灰度发布,一鼓作气,行云流水;
  • 稳定:系统健壮性良好,任尔东西南北风,咱们系统岿然不动。整年系统可用性 N 多个 9;
  • 高效:节约出更多人力,实现“快乐工做,认真生活”。

然而理想很丰满,现实很骨感。迎接咱们的倒是杂乱和形态万千的窘迫。

杂乱,是由于做为一个异军突起的新型技术栈,不少配套工具和工做流的建设处于初级阶段。Demo 版本中运行良好的工具,在真实场景下大规模铺开,各类隐藏的问题就会暴露无遗,层出不穷。从开发到运维,全部的工做人员都在各类被动地疲于奔命。另外,“大规模铺开”还意味着,要直接面对形态万千的生产环境:异构配置的机器、复杂的需求,甚至是适配用户的既往的使用习惯等等。

除了让人心力交瘁的混乱,系统还面临着应用容器的各类崩溃问题:内存不足致使的 OOM,CPU quota 分配太少,致使进程被 throttle,还有带宽不足,响应时延大幅上升...甚至是交易量在面对访问高峰时候因为系统不给力致使的断崖式下跌等等。这些都使咱们在大规模商用 Kubernetes 场景中积累很是多的经验。

直面问题

稳定性

问题总要进行面对的。正如某位高人说过:若是感受哪里不太对,那么确定有些地方出问题了。因而咱们就要剖析,问题究竟出在哪里。针对于内存的 OOM,CPU 资源被 throttle,咱们能够推断咱们给与容器分配的初始资源不足。

资源不足就势必形成整个应用服务稳定性降低。例如上图的场景:虽然是同一种应用的副本,或许是因为负载均衡不够强大,或者是因为应用自身的缘由,甚至是因为机器自己是异构的,相同数值的资源,可能对于同一种应用的不一样副本并具备相等的价值和意义。在数值上他们看似分配了相同的资源,然而在实际负载工做时,极有可能出现的现象是肥瘦不均的。

而在资源 overcommit 的场景下,应用在整个节点资源不足,或是在所在的 CPU share pool 资源不足时,也会出现严重的资源竞争关系。资源竞争是对应用稳定性最大的威胁之一。因此咱们要尽力在生产环境中清除全部的威胁。

咱们都知道稳定性是件很重要的事情,尤为对于掌控上百万容器生杀大权的一线研发人员。或许不经心的一个操做就有可能形成影响面巨大的生产事故。

所以,咱们也按照通常流程作了系统预防和兜底工做。

  • 在预防维度,咱们能够进行全链路的压力测试,而且提早经过科学的手段预判应用须要的副本数和资源量。若是无法准确预算资源,那就只采用冗余分配资源的方式了。
  • 在兜底维度,咱们能够在大规模访问流量抵达后,对不紧要的业务作服务降级并同时对主要应用进行临时扩容。

可是对于陡然增长几分钟的突增流量,这么多组合拳的花费不菲,彷佛有些不划算。或许咱们能够提出一些解决方案,达到咱们的预期。

资源利用率

回顾一下咱们的应用部署状况:节点上的容器通常分属多种应用,这些应用自己不必定,也通常不会同时处于访问的高峰。对于混合部署应用的宿主机,若是能都错峰分配上面运行容器的资源或许更科学。

应用的资源需求可能就像月亮同样有阴晴圆缺,有周期变化。例如在线业务,尤为是交易业务,它们在资源使用上呈现必定的周期性,例如:在凌晨、上午时,它的使用量并非很高,而在午间、下午时会比较高。

打个比方:对于 A 应用的重要时刻,对于 B 应用可能不那么重要,适当打压 B 应用,腾挪出资源给 A 应用,这是个不错的选择。这听起来有点像是分时复用的感受。可是若是咱们按照流量峰值时的需求配置资源就会产生大量的浪费。

除了对于实时性要求很高的在线应用外,咱们还有离线应用和实时计算应用等:离线计算对于 CPU 、Memory 或网络资源的使用以及时间不那么敏感,因此在任什么时候间段它均可以运行;实时计算,可能对于时间敏感性就会很高。

早期,咱们业务是在不一样的节点按照应用的类型独立进行部署。从上面这张图来看,若是它们进行分时复用资源,针对实时性这个需求层面,咱们会发现它实际的最大使用量不是 2+2+1=5,而是某一时刻重要紧急应用需求量的最大值,也就是 3 。若是咱们可以数据监测到每一个应用的真实使用量,给它分配合理值,那么就能产生资源利用率提高的实际效果。

对于电商应用,对于采用了重量级 Java 框架和相关技术栈的 Web 应用,短期内 HPA 或者 VPA 都不是件容易的事情。

先说 HPA,咱们或许能够秒级拉起了 Pod,建立新的容器,然而拉起的容器是否真的可用呢。从建立到可用,可能须要比较久的时间,对于大促和抢购秒杀-这种访问量“洪峰”可能仅维持几分钟或者十几分钟的实际场景,若是咱们等到 HPA 的副本所有可用,可能市场活动早已经结束了。

至于社区目前的 VPA 场景,删掉旧 Pod,建立新 Pod,这样的逻辑更难接受。因此综合考虑,咱们须要一个更实际的解决方案弥补 HPA 和 VPA 的在这一单机资源调度的空缺。

解决方案

交付标准

咱们首先要对解决方案设定一个能够交付的标准那就是—— “既要稳定性,也要利用率,还要自动化实施,固然若是可以智能化那就更好”,而后再交付标准进行细化:

  • 安全稳定:工具自己高可用。所用的算法和实施手段必须作到可控;
  • 业务容器按需分配资源:能够及时根据业务实时资源消耗对不过久远的未来进行资源消耗预测,让用户明白业务接下来对于资源的真实需求;
  • 工具自己资源开销小:工具自己资源的消耗要尽量小,不要成为运维的负担;
  • 操做方便,扩展性强:能作到无需接受培训便可玩转这个工具,固然工具还要具备良好扩展性,供用户 DIY;
  • 快速发现 & 及时响应:实时性,也就是最重要的特质,这也是和HPA或者VPA在解决资源调度问题方式不一样的地方。

设计与实现

上图是咱们最初的工具流程设计:当一个应用面临很高的业务访问需求时,体如今 CPU、Memory 或其余资源类型需求量变大,咱们根据 Data Collector 采集的实时基础数据,利用 Data Aggregator 生成某个容器或整个应用的画像,再将画像反馈给 Policy engine。 Policy engine 会瞬时快速修改容器 Cgroup 文件目录下的的参数。

咱们最先的架构和咱们的想法同样朴实,在 kubelet 进行了侵入式的修改。虽然咱们只是加了几个接口,可是这种方式确实不够优雅。每次 kubenrnetes 升级,对于 Policy engine 相关组件升级也有必定的挑战。

为了作到快速迭代并和 Kubelet 解耦,咱们对于实现方式进行了新的演进。那就是将关键应用容器化。这样能够达到如下功效:

  • 不侵入修改 K8s 核心组件;
  • 方便迭代&发布;
  • 借助于 Kubernetes 相关的 QoS Class 机制,容器的资源配置,资源开销可控。

固然在后续演进中,咱们也在尝试和 HPA,VPA 进行打通,毕竟这些和 Policy engine 存在着互补的关系。所以咱们架构进一步演进成以下情形。当 Policy engine 在处理一些更多复杂场景搞到无力时,上报事件让中心端作出更全局的决策。水平扩容或是垂直增长资源。

下面咱们具体讨论一下 Policy engine 的设计。Policy engine 是单机节点上进行智能调度并执行 Pod 资源调整的核心组件。它主要包括 api server,指挥中心 command center 和执行层 executor。

  • 其中 api server 用于服务外界对于 policy engine 运行状态的查询和设置的请求;
  • command center 根据实时的容器画像和物理机自己的负载以及资源使用状况,做出 Pod 资源调整的决策;
  • Executor 再根据 command center 的决策,对容器的资源限制进行调整。同时,executor 也把每次调整的 revision info 持久化,以便发生故障时能够回滚。

指挥中心按期从 data aggregator 获取容器的实时画像,包括聚合的统计数据和预测数据,首先判断节点状态,例如节点磁盘异常,或者网络不通,表示该节点已经发生异常,须要保护现场,再也不对Pod进行资源调整,以避免形成系统震荡,影响运维和调试。若是节点状态正常,指挥中心会策略规则,对容器数据进行再次过滤。好比容器 CPU 率飙高,或者容器的响应时间超过安全阈值。若是条件知足,则对知足条件的容器集合给出资源调整建议,传递给executor。

在架构设计上,咱们遵循了如下原则:

  • 插件化:全部的规则和策略被设计为能够经过配置文件来修改,尽可能与核心控制流程的代码解耦,与 data collector 和 data aggregator 等其余组件的更新和发布解耦,提高可扩展性;

  • 稳定,这包括如下几个方面:

    • 控制器稳定性。指挥中心的决策以不影响单机乃至全局稳定性为前提,包括容器的性能稳定和资源分配稳定。例如,目前每一个控制器仅负责一种 cgroup 资源的控制,即在同一时间窗口内,Policy engine 不一样时调整多种资源,以避免形成资源分配震荡,干扰调整效果;
    • 触发规则稳定性。例如,某一条规则的原始触发条件为容器的性能指标超出安全阈值,可是为避免控制动做被某一突发峰值触发而致使震荡,咱们把触发规则定制为:过去一段时间窗口内性能指标的低百分位超出安全阈值;若是规则知足,说明这段时间内绝大部分的性能指标值都已经超出了安全阈值,就须要触发控制动做了;
    • 另外,与社区版  Vertical-Pod-Autoscaler 不一样,Policy engine 不主动驱逐腾挪容器,而是直接修改容器的 cgroup 文件;
  • 自愈:资源调整等动做的执行可能会产生一些异常,咱们在每一个控制器内都加入了自愈回滚机制,保证整个系统的稳定性;

  • 不依赖应用先验知识:为全部不一样的应用分别进行压测、定制策略,或者提早对可能排部在一块儿的应用进行压测,会致使巨大开销,可扩展性下降。咱们的策略在设计上尽量通用,尽可能采用不依赖于具体平台、操做系统、应用的指标和控制策略。

在资源调整方面,Cgroup 支持咱们对各个容器的 CPU、内存、网络和磁盘 IO 带宽资源进行隔离和限制,目前咱们主要对容器的 CPU 资源进行调整,同时在测试中探索在时分复用的场景下动态调整 memory limit 和 swap usage 而避免 OOM 的可行性;在将来咱们将支持对容器的网络和磁盘 IO 的动态调整。

调整效果

k10

上图展现了咱们在测试集群获得的一些实验结果。咱们把高优先级的在线应用和低优先级的离线应用混合部署在测试集群里。SLO 是 250ms,咱们但愿在线应用的 latency 的 95 百分位值低于阈值 250ms。

在实验结果中能够看到:

  • 在大约90s前,在线应用的负载很低;latency 的均值和百分位都在 250ms 如下;
  • 到了  90s后,咱们给在线应用加压,流量增长,负载也升高,致使在线应用 latency 的 95 百分位值超过了 SLO;
  • 在大约 150s 左右,咱们的小步快跑控制策略被触发,渐进式地 throttle 与在线应用发生资源竞争的离线应用;
  • 到了大约 200s 左右,在线应用的性能恢复正常,latency 的 95 百分位回落到 SLO 如下。

这说明了咱们的控制策略的有效性。

经验和教训

下面咱们总结一下在整个项目的进行过程当中,咱们收获的一些经验和教训,但愿这些经验教训可以对遇到相似问题和场景的人有所帮助。

  1. 避开硬编码,组件微服务化,不只便于快速演进和迭代,还有利于熔断异常服务。
  2. 尽量不要调用类库中仍是 alpha 或者 beta 特性的接口。 例如咱们曾经直接调用 CRI 接口读取容器的一些信息,或者作一些更新操做,可是随着接口字段或者方法的修改,共建有些功能就会变得不可用,或许有时候,调用不稳定的接口还不如直接获取某个应用的打印信息可能更靠谱。
  3. 基于 QoS 的资源动态调整方面:如咱们以前所讲,阿里集团内部有上万个应用,应用之间的调用链至关复杂。应用 A 的容器性能发生异常,不必定都是在单机节点上的资源不足或者资源竞争致使,而颇有多是它下游的应用 B、应用 C,或者数据库、cache 的访问延迟致使的。因为单机节点上这种信息的局限性,基于单机节点信息的资源调整,只能采用“尽力而为”,也就是 best effort 的策略了。在将来,咱们计划打通单机节点和中心端的资源调控链路,由中心端综合单机节点上报的性能信息和资源调整请求,统一进行资源的从新分配,或者容器的从新编排,或者触发 HPA,从而造成一个集群级别的闭环的智能资源调控链路,这将会大大提升整个集群维度的稳定性和综合资源利用率。
  4. 资源v.s.性能模型:可能有人已经注意到,咱们的调整策略里,并无明显地提出为容器创建“资源v.s.性能”的模型。这种模型在学术论文里很是常见,通常是对被测的几种应用进行了离线压测或者在线压测,改变应用的资源分配,测量应用的性能指标,获得性能随资源变化的曲线,最终用在实时的资源调控算法中。在应用数量比较少,调用链比较简单,集群里的物理机硬件配置也比较少的状况下,这种基于压测的方法能够穷举到全部可能的状况,找到最优或者次优的资源调整方案,从而获得比较好的性能。可是在阿里集团的场景下,咱们有上万个应用,不少重点应用的版本发布也很是频繁,每每新版本发布后,旧的压测数据,或者说资源性能模型,就不适用了。另外,咱们的集群不少是异构集群,在某一种物理机上测试获得的性能数据,在另外一台不一样型号的物理机上就不会复现。这些都对咱们直接应用学术论文里的资源调控算法带来了障碍。因此,针对阿里集团内部的场景,咱们采用了这样的策略:不对应用进行离线压测,获取显示的资源性能模型。而是创建实时的动态容器画像,用过去一段时间窗口内容器资源使用状况的统计数据做为对将来一小段时间内的预测,而且动态更新;最后基于这个动态的容器画像,执行小步快跑的资源调整策略,边走边看,尽力而为。

总结与展望

总结起来,咱们的工做主要实现了如下几方面的收益:

  • 经过分时复用以及将不一样优先级的容器(也就是在线和离线任务)混合部署,而且经过对容器资源限制的动态调整,保证了在线应用在不一样负载状况下都能获得足够的资源,从而提升集群的综合资源利用率。
  • 经过对单机节点上的容器资源的智能动态调整,下降了应用之间的性能干扰,保障高优先级应用的性能稳定性
  • 各类资源调整策略经过 Daemonset 部署,能够自动地、智能地在节点上运行,减小人工干预,下降了运维的人力成本。

展望将来,咱们但愿在如下几个方面增强和扩展咱们的工做:

  • 闭环控制链路:前面已经提到,单机节点上因为缺少全局信息,对于资源的调整有其局限性,只能尽力而为。将来,咱们但愿可以打通与 HPA 和 VPA 的通路,使单机节点和中心端联动进行资源调整,最大化弹性伸缩的收益。
  • 容器从新编排:即便是同一个应用,不一样容器的负载和所处的物理环境也是动态变化的,单机上调整 pod 的资源,不必定可以知足动态的需求。咱们但愿单机上实时容器画像,可以为中心端提供更多的有效信息,帮助中心端的调度器做出更加智能的容器重编排决策。
  • 策略智能化:咱们如今的资源调整策略仍然比较粗粒度,能够调整的资源也比较有限;后续咱们但愿让资源调整策略更加智能化,而且考虑到更多的资源,好比对磁盘和网络IO带宽的调整,提升资源调整的有效性。
  • 容器画像精细化:目前的容器画像也比较粗糙,仅仅依靠统计数据和线性预测;刻画容器性能的指标种类也比较局限。咱们但愿找到更加精确的、通用的、反映容器性能的指标,以便更加精细地刻画容器当前的状态和对不一样资源的需求程度。
  • 查找干扰源:咱们但愿能找到在单机节点上找到行之有效的方案,来精准定位应用性能受损时的干扰源;这对策略智能化也有很大意义。

Q & A

**Q1:**直接修改 cgroup 容器必定会得到资源吗? **A1:**容器技术隔离的技术基础就是 cgroup 层面。在宿主机腾出足够资源的状况下,给 cgroup 设置更大的值能够获取更多的资源。同理,对于通常优先级不高的应用,设置较低的 cgroup 资源值就会达到抑制容器运行的效果。

**Q2:**底层是如何区分在线和离线优先级的? **A2:**底层是没法自动获取谁是在线,谁是离线,或者谁的优先级高,谁的优先级低的。这个咱们能够经过各类 Kubernetes 提供的扩展实现。最简单的是经过 label,Annotation 标识。固然经过扩展 QoS class 也是一种思路。社区版本的 QoS class设置太过于保守,给予用户发挥的空间不大。咱们经过这些方面也进行了加强。在合适的时候或许会推向社区。自动感知是个方向,感知谁是干扰源,感知谁是某种资源型应用,这块咱们还在研发中。作到真正的动态,确定是具有自动感知的智能系统。

Q3:“与社区版  Vertical-Pod-Autoscaler 不一样,Policy engine 不主动驱逐腾挪容器,而是直接修改容器的 cgroup 文件”,想问一下,不主动驱逐的话,若是 Node 的资源达到上线了会怎么处理? **A3:**这是一个好问题。首先这里要先区分是哪一种资源,若是是 CPU 型的,咱们能够调整低优先级容器的 cgroup 下 cpu quota 的值,首先抑制低优先级的容器对于 CPU 的争抢。而后再适当上调高优先级容器的相关资源值。若是是内存型资源,这个不能直接去缩小低优先级容器的 cgroup 值,不然会形成 OOM,对于学习内存型资源的调整,咱们会在其余分享中继续讨论。这个技术比较特殊。

**Q4:**只修改 cgroup,怎么保证 K8s 对单个物理机可以分配更多的容器? **A4:**文字直播有了必定说明,容器的资源消耗并不是是一成不变的,不少时候它们的资源消耗呈现潮汐现象,相同的资源条件下部署更多应用,完成更多做业就是达到资源利用的最大化的效果。资源出现超卖才是咱们这个主题讨论的最大价值。

**Q5:**也就是说,低优先级的容器,request 设置的比 limit 小不少,而后大家再动态的调整 cgroup? **A5:**在现有 QoS 场景下,你能够理解被调整的 Pod 都是 burstable 的。可是咱们并非直接调整 Pod 元数据的 limit 的值,而是调整 limit 在 cgroup 反映的值,这个值在资源竞争缓和的时候还会被调整回去的。咱们并不建议单机的 cgroup 数据和 etcd 的中心数据割裂过久。若是长期偏离,咱们会像 VPA 发出警报,联动 VPA 作调整。固然在容器运行的高峰期,任何重建容器的操做都是不明智的。

**Q6:**总体的理解就是大家开始就让物理机超配了必定比例的 pod,而后经过策略动态调整容器的 cgroup 值? **A6:**若是资源彻底是富足冗余的,这个动态调整也有必定意义。就是并不是资源用满场景下,高优先级应用会被干扰,实际上,当主机的 CPU 达到必定比例,打个比方例如 50%,应用的时延就变大。为了彻底确保高优先级应用的 SLO,牺牲低优先级的 CPU 正常运行也是有价值的。

**Q7:**Policy engine 有没有考虑开源? **A7:**有计划进行开源,Policy engine 更多的是和自身的应用属性相关,电商应用或者大数据处理应用的策略都是不相同的,咱们开源会首先开源框架和附带一些简单的策略,更多的策略能够用户自定义。

**Q8:**我以前遇到的大部分应用都没法正确感知 cgroup 的配置,所以不少状况都须要在启动参数里面根据 cpu 或者 mem 设置参数,那么也就是说即便改变了 cgroup 对于他们来讲都无效,那么使用场景也就有限了 **A8:**限制容器的资源使用这个仍是有价值的。限制低优先级应用自己也能够提高高优先级应用的 SLO,虽然效果没有那么明显。稳定性的考量一样也很重要。

**Q9:**Policy engine 目前在阿里的使用如何?在生产上有多上的规模使用这种方式进行动态调整?是否和社区的 HPA VPA 配合使用? **A9: **Policy engine 在阿里某些集群已经使用。至于规模暂时没法透漏。涉及到不少组件之间的联动,社区的 HPA 和 VPA 目前都不太能知足咱们的需求。所以阿里的 HPA 和 VPA 都是咱们自行开发的,可是和社区的原理是一致的。阿里 HPA 的开源能够关注 Openkruise 社区。VPA 开源计划我这里尚未确切消息。

**Q10:**当单机节点资源不足以提供容器扩容时,目前是否能够进行 HPA 或 VPA 扩容呢? **A10:**单机节点不足的时候,应用能够经过 HPA 进行增长副本应对。可是 VPA 若是选择原节点进行更新的话,是失败的。只能调度到其余资源丰富的节点。在流量陡升的场景下,重建容器未必能知足需求,极可能致使雪崩,即重建过程当中,整个应用其余未升级的副本接受更多流量,OOM 掉,新启动的容器再瞬间被 OOM,因此重启容器须要慎重。快速扩容(HPA)或者快速提高高优先级资源,抑制低优先级容器资源的方式效果更明显。

关注『阿里巴巴云原生』公众号,回复关键词“1010”,可获取本文 PPT

“ 阿里巴巴云原生微信公众号(ID:Alicloudnative)关注微服务、Serverless、容器、Service Mesh等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,作最懂云原生开发者的技术公众号。”

原文出处:https://www.cnblogs.com/alisystemsoftware/p/11658705.html

相关文章
相关标签/搜索