在云原生场景下,为了使CPU利用率更高,以及各容器之间不会由于激烈竞争而引起性能下降,容器的资源分配需要更精细化。
中国信通院、腾讯云、FinOps产业标准工作组联合发起的《原动力x云原生正发声 降本增效大讲堂》系列直播活动,腾讯星辰算力平台高级工程师方睿分享了Kubernetes资源拓扑感知调度。
资源竞争与资源感知问题
从CPU的体系结构上来看,现代CPU多采用NUMA架构和方式。
NUMA架构是非对称的,每个NUMA node上会有自己的物理CPU内核,以及每个NUMA node之间也共享L3 Cache。同时,内存也分布在每个NUMA node上的。某些开启了超线程的CPU,一个物理CPU内核在操作系统上会呈现两个逻辑的核。
实际上,CPU内核是分布在NUMA node上,NUMA node内本身就有一些亲和性的元素。
右图中,CPU开始的访问速度是不一样的。
如果程序都跑在同一个NUMA node上,可以更好地去共享一些L3 Cache,L3 Cache的访问速度会很快。如果L3 Cache没有命中,可以到内存中读取数据,访存速度会大大降低。
因此,从CPU体系结构中可以看到,如果采用一些错误的CPU分配方式,可能会导致进程访存速度急剧下降,严重影响应用程序的性能。
在这样的体系结构下,存在云计算中常见的吵闹的邻居问题。当多个容器在节点上共同运行时,由于资源分配的不合理,会对CPU本身的性能造成影响。
从理想的使用方式来看,如果每个进程都使用各自的CPU内核,并且不会跨NUMA node访问,相互之间不会有太多争抢。
从糟糕的使用方式来看,如果两个进程的CPU内核在分配时,可能会没有遵循NUMA的亲和性,会带来很大的性能问题,体现在三个方面:
Kubernetes中有CPU Manager的功能,CPU Manager可以做一些CPU核心的分配工作。上图是Kubernetes的一些数据呈现。
在吵闹的邻居问题下,Kubernetes是如何解决的呢?
CPU Manager是其中的一个解决方法,它被放在Kubelet中,CPUSet将会被CPU Manager分在Default和Exclusive两个池子中。
但原生Kubernetes也存在局限性。
Kubernetes中调度器只负责为Pod选择节点,并不感知节点NUMA拓扑结构,Pod的CPU分配交给Kubelet完成。当节点单NUMA node上没有足够的CPU时,Pod启动失败,控制器重建Pod后会陷入死循环。
Kubernetes中CPU Manager默认为请求整数CPU的Guaranteed Pod分配独占的CPUSet,但实际上Pod想定制自己的CPU分配策略,可能只是想分配到一个NUMA node内,或是固定CPU甚至是不做绑核。
在混部场景下,也存在离线算力感知问题。
如果忙时调度过多的离线任务,会导致剧烈的资源争抢,并且每个离线Pod的性能都会下降。
因此,调度器在调度时,需要动态感知离线实时算力。驱逐器也应当在线严重干扰离线时,驱逐离线Pod,保证节点的算力稳定。
Kubernetes精细化调度
如上图,是精细化调度系统的结构。
扩展调度器是通过Scheduler-Plugins来实现的,可以在几个插入点做一些插件,保证实现标库资源头部感知调度的功能。
在调度算法上,可以从性能和负载均衡两个方面做出考虑,以便更好地选择节点和拓扑。
容器CPUSet管理
Kubernetes的精细化调度做出一些拓扑感知,而实际落到节点上,为了更好地实现资源分配,我们设计了一个资源分配系统。
关于容器多级资源QoS分配策略,在CPUSet的策略上,可以划分为四种:
在CPU内核心选择策略上:
在离线混部场景下的实践
由于离线混部场景中,离线会受到在线的影响,算力是波动的。因此,在离线混部场景下,还会做一些差异化重调度:
在不同混部场景下,容器CPUSet策略也是不同的。
离线CVM混部的场景中,一台物理机的各个NUMA node上都生产了许多在线的CVM,当在线利用率很低时,需要更好地利用资源。
此时需要采取Exclusive策略:
在容器混部的场景中,在线Pod和离线Pod同时部署在同一台物理机上。
此时需要采取NUMA策略:
总结
本文围绕Kubernetes的资源拓扑感知调度的主题展开。从CPU体系结构和吵闹的邻居问题切入,随后阐述了原生Kubernetes的不足和混部场景下的算力感知的局限,最后从采集节点拓扑资源、扩展Kubernetes调度器、多级资源QoS分配策略几个方面给出了相应的解决方案。在策略的优化后,资源得到更合理地利用。
未来,Kubernetes精细化调度将会覆盖更多的场景,例如碎片GPU、网络拓扑架构、电力调度。
点关注,不迷路~~~