众所周知,假期出行,热情高涨,需求增多也使得稳定性保障压力大。当各个服务流量激增时,资源负载压力将会显著提升。微观上,单台物理机的 CPU 利用率会大幅提升,单机上各个容器之间的争抢会增加,性能受到影响。宏观上,整个弹性云的热点机器会增加,可供调度的资源会降低,容器调度和扩容的失败率会上升。
今年,在降本增效的大前提下,不额外增加计算型服务器采购,如何保障资源供给以及确保高压场景下的容器稳定性,对弹性云而言是个巨大的挑战。为了提供更稳定的容器服务,弹性云全面梳理了容器服务资源保障的每一个环节,提出了新分级保障体系,提供了明确的容器资源保障等级,在此基础上,针对不同优先级的容器提供相应的资源和稳定性保障。
弹性云早期分级体系提供了1/2/3级容器等级,只是对容器的优先级进行了简单的区分,并未将容器优先级与底层的资源保障关联在一起。容器服务在使用过程中,会遇到以下问题:
之所以会存在这些问题,实际上还是因为在资源层面没有相应的保障。从单机资源看,部分物理机的 CPU 使用率峰值过高,并且容器的 CPU 资源存在不同程度的超卖。
从集群资源来看,旧体系下 quota 与物理机资源缺乏关联,导致业务申请的 quota 仅仅停留在数字层面,不指导物理机资源的准备。此外,quota 还缺乏管控,导致 quota 的申请与实际需求严重脱节。
造成上述诸多问题很重要的一个原因就是弹性云资源整体上是超卖的,且比较严重。
所谓的资源超卖,指的是资源的申请量>供给量,表现为单机 & 集群方面均超卖。
从上图中可以看到,单是1级服务申请的资源量,就已经超过了物理机的总资源量。在集群和单机都超卖的情况下,早期的分级体系并没有确立明确的超卖规则,使得旧体系容器运行环境整体处于无序和不确定的状态下。
所有的核心服务链路上的服务均1:1对应物理机资源,不超卖。通过对机房1和机房2进行简单的统计, 发现核心服务链路中网约车+两轮车+代驾服务的申请量总和占据了所有服务总申请量的大约一半,且机房1核心服务的申请量已经超过总CPU数,机房2核心服务的申请量基本接近总CPU数。所以,核心服务不超卖受限于资源,方式不可行。
受限于资源,无法做到所有的核心服务链路中的服务都不超卖,那退一步,在物理资源有限的情况下,保障核心服务链路中最重要的服务不超卖,并在此基础上,对于剩余的服务制定合理的超卖规则。
因此,弹性云需要重新制定分级保障体系,同时为新分级体系制定明确的超卖规则。超卖规则如下:
在新的超卖规则下,可以看到,机房1和机房2的总物理CPU量是基本能满足需求的(机房2的资源申请量略微超出, 可以通过新增机器或是缩容来满足要求)。
这样的重新设计下,我们在2022年元旦前完成所有S级服务的接入,2022年国庆前完成网约车核心服务/两轮车核心服务/代驾核心服务接入新体系。总体来看,这样的改变带来了四大收益:
为了支持新分级保障体系,弹性云从下到上,针对每一层中的相关组件都进行开发改造,同时也包含了系统部 CMP 系统quota相关的开发工作,主要体现在操作系统层、k8s 调度层、kube-odin 层、服务树和系统部 CMP 系统。
从上述架构图中可以看到,位于最底层的是机房的物理机资源,物理机分别位于不同的机房。
物理机之上是操作系统层,操作系统层面分为内核态和用户态。在内核态新增特性上,新分级体系对 CPU 调度,内存管理,IO 读写都进行了针对性的开发和优化。
CPU 调度:
内存管理:
IO 读写:
在用户态新增特性上,操作系统用户态针对新分级体系的支持主要体现在 Kubelet、IRMAS 和单机资源调度这几个组件上。其中,kubelet 和 IRMAS 主要新增了新分级体系容器的识别、信息采集上报、单机资源配置、环境适配等工作。新增单机资源调度模块实现了极端情况下单机资源的压制和恢复,以及与 k8s 调度联动等功能。
在 k8s 容器调度层,针对新分级体系新增了最小资源保障策略,指的是通过合理的调度,保障任何时候,容器均能获得承诺的资源量。
容器分级均衡打散策略指的是保证一台物理机上不会存在过多同一级别的容器,将不同等级的容器均匀打散到不同的物理机上。
分级容量资源大盘指的是资源大盘新增新分级体系容器支持,实时观察新分级容器容量健康情况。
扩容成功率保障指的是新增容量预估特性,优化资源申请流程,实时监控弹性云可供扩容资源量,有效提高扩容成功率。
kube-odin 层配合新分级体系也进行了相关改动和升级:
服务树在保持兼容性的基础上,新增了新分级体系集群信息的支持。
新体系容器的 quota 申请和使用由系统部 CMP 系统操作和记录。
CMP 系统通过获取业务申请的 quota 信息,能明确推算所需的物理机资源,更好实现物理机资源的保障。针对新体系容器的 quota 支持,CMP 系统新增了 quota 成本账户、quota 成本账户以及 quota 申请模块。
新分级体系立足于核心问题,在单机层面和集群层面都对容器申请的资源进行相应保障。
新分级体系资源保障的其中一个重点为:保障容器的 CPU 资源任何时刻都能按超卖比所规定的有效交付。
在前文中,我们提到新体系容器的超卖规则为:S级不超卖,A级2倍超卖,B级4倍超卖。那对于不同等级的容器,可轻松得知其所需的物理 CPU 个数。新分级体系所需要保证的就是一台物理机上所有容器经过超卖比计算后得到的物理 CPU 个数必须小于物理机上的 CPU 个数。
图片
上述的示例中,对于一个40核的物理机,可用的 CPU 数为: 40*90%=36核 (90%为计算各种 agent 和调度损耗之后的有效核数)。容器总共申请的核数为56核,经过超卖比计算后得到的所需物理核为36,刚好满足要求。
通过明确超卖比,根据超卖比准备对应物理 CPU 资源的方式,在高负载期间,如果所有的容器都满载运行,则物理机上的 CPU 资源将会按照超卖比承诺的比例进行分配。在低负载时刻,算力足够时,由于机器整体空闲,容器之间几乎不发生争抢,此时容器可以正常使用 CPU。
在物理机层面,内存是所有容器之间共享的资源,传统内核没有对容器进行优先级的划分,所有容器的内存使用对于内核而言都是一视同仁。
内存对容器性能的影响主要体现在内存分配和内存回收上。
操作系统内核会监控整个系统的内存使用情况,当可用内存低于一定水位时,就会阻塞内存分配路径,触发内存回收操作。
某些场景下,低优先级容器可能大量申请内存,导致内存水位线降职 min 水位以下,物理机面临内存分配和回收时,高优容器将会受到影响,无法及时的分配内存。
针对这个场景,内核新增了内存分级水位特性,允许按照优先级设置不同的 min 水位。这样,在申请内存时,低优先级容器会先达到回收水位线触发低优先级容器的内存回收,而高优先级容器的内存回收水位线较低,可以正常分配。
由于原生内存没有对内存进行优先级区分,因此当内核走到内存回收路径,会无差别的进行内存回收动作。此时,可能高优先级容器的内存被回收,而低优先级容器内存则完好无损。
新分级体系的目标显然是要在回收内存的时候优先回收低优先级容器的内存,这样可以最大程度保护高优先级容器的内存,进而保障高优先级容器的性能表现。
图片
基于优先级回收的思想,内核所做的就是识别容器优先级,然后按照容器优先级逐一回收内存,直至内存水位线恢复健康水平。
先回收B级容器的内存
再回收A级容器的内存
业务在申请容器服务的时候,一般需要指定单个容器的规格(CPU/内存大小)和申请的数量。汇总服务总共所需的资源量,即为 quota,quota 管理的最小单位为成本账户。
图片
可以看到,在新分级体系下,quota 按照容器优先级,分为了对应的S级/A级/B级 quota。quota 是用于描述业务的资源申请量,而对于弹性云和系统部而言, 则可以根据 quota,进行物理资源的准备。例如对于某个成本账户,申请的 quota 如下所示:
图片
我们可以清楚看到,业务申请的 quota 量与实际准备物理机资源量之间的对应关系。
通过建立并规范 quota 的申请和使用流程,新分级体系能根据资源超卖规则有效的将 quota 的申请量与后台真实物理资源的准备量结合起来,从而实现资源层面的强保障。另外,在 quota 体系逐步完善之后,还能根据 quota 使用率和容器的 CPU 使用率对 quota 进行有效的资源管控。
很长一段时间,旧的弹性云分级体系存在资源争抢、业务延迟、扩容失败、业务无法准确评估容量、物理机数量难以评估等问题。这些问题的本质是由于没有制定明确的资源准备和分配规则。
新分级体系立足于核心问题,提出了明确的资源超卖规则,在单机层面和集群层面都对容器申请的资源进行相应保障。在单机层面,保证了按超卖比转化后实际的物理机资源不会超过物理机所提供的最大资源量,同时制定了明确的资源争抢规则。在集群层面,建立并规范了 quota 申请流程,明确了 quota 与物理机资源之间的对应关系,保障了资源的供给,同时,也有效管控了 quota ,避免资源的浪费。
通过在容器资源申请、容器调度、运行时保障、资源管控等多个方面添加资源保障策略,弹性云新分级体系支持容器高效稳定的运行,确保了弹性云整体的稳定性,也一定程度降低了物理机运营成本。