本期作者

许龙

哔哩哔哩资深开发工程师

2020年加入B站,负责k8s云平台相关研发工作,包括容器和k8s引擎、混部、弹性伸缩等。

01 背景

中大型互联网公司的服务器数量可达万级别,在降本增效的大背景下,机器资源利用率的重要性日益凸显。如何在确保服务SLO影响最小的情况下提高机器资源利用率,从而降低服务器的采购成本,是一项非常值得研究的课题。

对于k8s云平台来说,造成机器平均资源利用率低的原因可以概括为以下几点:

  1. 业务申请的资源配额超过实际使用量。 即用户在申请资源时可能会对服务的真实资源使用情况估计不足,一般倾向于申请过量的资源。这就导致机器配额被占满,无法继续调度容器,而实际资源利用率却很低。
  2. 服务的资源使用量存在波峰波谷。 大部分服务的负载都会存在高低峰,当服务处于波谷的时候就会存在很大的资源浪费。

针对上述问题1),我们可以通过服务画像给业务推荐一个合理的资源配置值,并结合弹性伸缩的手段来解决。

针对上述问题2),关键点在于如何将业务波谷时空闲出来的那部分资源利用起来,比如凌晨在线业务处于波谷的时候,往在线集群调度适量的离线任务。

目前B站私有云平台已经达到较大的机器规模,我们从上述两个思路出发来给整体云平台降本:一方面提供了hpa和vpa的弹性伸缩能力,使得业务资源配额使用更为合理;另一方面,我们实施了较大规模的业务混部来解决算力的闲置问题。本文将主要分享B站云平台的混部实践,而弹性伸缩方面的实践我们会择机在后续文章中介绍。

02 混部的概念

我们把业务划分为在线业务和离线业务。在线业务一般是各类微服务,特点是延时敏感、有很高的可用性要求,如推荐、广告、搜索等服务;离线业务一般是批处理任务,特点是延时不敏感、允许出错重跑,如大数据场景中的MapReduce任务、视频处理中的转码任务等。 所谓混部技术,就是通过调度、资源隔离等手段,将不同类型、不同优先级的在离线业务部署在相同的物理机器上,并且保证业务的SLO,最终达到提高资源利用率、降低成本的目的。 需要注意的是,混部不是简单地将容器部署到同一台宿主机上,而是需要通过调度算法将混部任务调度到具有空闲资源的机器,同时需要有隔离机制来保证高优任务不会受到混部任务的干扰。

03 B站混部的场景

1. 在离线混部 。B站是一个视频类网站,存在大量的点播视频转码任务,这类任务属于计算密集型,具有运行时间短、允许失败重试等特点。另外,在凌晨时段会触发大量的转码定时任务,刚好和在线业务形成错峰。我们通过在离线混部技术将转码任务调度到在线集群,既提高了在线集群的资源使用率,又补充了转码任务高峰期时的算力缺口,极大地降低了服务器成本。这类混部场景的难点在于:

B站云原生混部技术实践(B站云原生混部技术实践)(1)

2. 离线间混部 。离线集群整体的cpu使用率较高,但部分时段也存在一定的资源闲置,例如训练平台在训练任务较少时整体利用率会偏低。由于都是离线任务,延时敏感性没有在线那么高,因此这类场景除了混部转码任务外,还可以混部一些更“重”的大数据任务。但是大数据任务通常用yarn调度,如何将k8s调度和yarn调度进行协调是我们需要解决的关键问题。实现了大数据混部后,我们就可以做到各个离线业务互相出让资源。例如将hdfs datanode机器接入k8s用于混部转码任务;反过来,转码的机器上也可以运行hadoop/spark等大数据任务。

B站云原生混部技术实践(B站云原生混部技术实践)(2)

3. 闲置机器混部 。IDC通常会存在一定量的备机,用于各业务应急场景使用,但是日常是闲置的。这部分机器我们也会自动化接入k8s跑混部任务,当业务需要借调备机时再自动下线混部。

下面,我们结合在离线混部和离线间混部这两个场景,具体介绍一下混部的关键技术点。

04 在离线混部4.1 总体架构

B站云原生混部技术实践(B站云原生混部技术实践)(3)

下面,我们从混部任务调度、在线QoS保障两方面来介绍在离线混部的关键技术点。

4.2 混部任务调度

k8s原生调度器的基本原理和问题

k8s的每个节点都会上报节点资源总量(例如allocatable cpu)。对于一个待调度的pod,k8s调度器会查看pod的资源请求配额(例如cpu reqeust)以及相关调度约束,然后经过预选和优选阶段,最终挑选出一个最佳的node用于部署该pod。如果混部任务直接使用这套原生的调度机制会存在几个问题:

  1. 混部pod会占用原生的资源配额(例如cpu request),这会导致在线任务发布的时候没有可用资源;
  2. 原生调度本质是静态调度,没有考虑机器实际负载,因此没法有效地将混部任务调度到实际负载有空闲的机器上。

基于扩展资源的混部调度

B站云原生混部技术实践(B站云原生混部技术实践)(4)

为了解决上述问题,我们基于k8s的扩展资源进行混部任务调度,整体分为3个步骤:

1. colocation agent模块中,策略组件会实时加载当前接收到的混部配置,并调用autopilot组件进行混部算力的计算,然后通过device-plugin组件上报混部扩展资源,例如caster.io/colocation-cpu

2. 混部任务在申请资源配额时,仍然申请原生cpu资源,但是会增加pod标签“caster.io/resource-type: colocation”。k8s webhook模块根据标签识别到混部pod,然后将pod申请的资源修改为混部扩展资源。这种方式对业务层屏蔽了底层扩展资源,通过标注pod标签即可指定是否使用混部资源。

B站云原生混部技术实践(B站云原生混部技术实践)(5)

3. 混部调度器job-scheduler根据pod申请的扩展资源量以及各个节点上报的混部扩展资源量进行调度。我们利用转码pod存在同质化(资源规格和调度约束相同)的特点对调度器进行了优化,基本思路是:

混部资源量计算

k8s node是怎么确定当前节点应该上报多少混部扩展资源量的呢?我们针对不同的应用场景设计了不同的混部策略算法:

1. 动态计算 。针对各类物理资源,例如cpu、memory等,我们会分别设置机器的安全水位值n%。agent会实时探测在线进程的资源使用量online_usage,然后根据安全水位和在线负载动态计算出可混部资源量。在线使用量和可混部资源量是此消彼长的,随着在线使用量上升,我们上报的可混部量就会下降,反之,当在线使用量下降,可混部量就会上升。

B站云原生混部技术实践(B站云原生混部技术实践)(6)

2. 静态计算 。例如备机池闲置机器没有在线业务,不需要动态资源计算,因此我们可以配置静态上报策略,上报固定的可混部资源量即可。

3. 分时计算 。如果部分在线业务在某些时间段不希望部署混部任务,我们就需要用到分时策略,即在某些时间段关闭混部或者减少上报混部资源量。另外,我们还支持设置grace period,在分时混部结束前,会提前停止调度混部任务到该k8s node,并等待存量任务结束,做到优雅退出。

4.3 在线QoS保障

资源隔离是混部架构的关键难点。我们希望在提高单机混部资源量的同时,尽可能地降低混部任务对在线业务的性能影响。主要从三个层次来保障在线业务的QoS:

下面我们详细介绍一下资源隔离层的几种策略。

混部大框

在前面的介绍中我们提到webhook会对混部任务申请的资源类型进行修改,去除原生的资源类型request.cpu和request.memory,改成caster.io/colocation-cpu和caster.io/colocation-memory。由于没有申请原生资源类型,那么k8s会自动将这类pod归类为best effort类型,并且最终通过runc将该类pod的cgroup设置到/sys/fs/cgroup/cpu/kubepods/besteffort目录,我们称为“混部大框”。

B站云原生混部技术实践(B站云原生混部技术实践)(7)

cpu动态隔离

在cgroup层面,我们给大框设置了最小的cpu share值,保证在资源争抢时,混部任务获得cpu时间片的权重最小。

colocation agent中的cgroup manager组件负责动态地调整“混部大框”的cpu quota,从而对混部任务进行整体的资源限制。 当colocation agent检测到在线负载降低时,就会调大“混部大框”的cpu quota,让混部任务充分利用空闲的算力。 当在线负载升高时,则是缩小“混部大框”的cpu quota,快速让出资源给在线业务 使用。

此外,我们通过cpuset cgroup对整体混部大框做了 绑核 处理,避免混部任务进程频繁切换干扰在线业务进程。 当混部算力改变时,agent会给大框动态选取相应的cpu核心进行绑定。 另外,选取cpu核心的时候也考虑了 cpu HT ,即尽量将同一个物理核上的逻辑核同时绑定给混部任务使用。 否则,如果在线任务和混部任务分别跑在一个物理核的两个逻辑核上,在线任务还 是有可能受到“noisy neighbor”干扰。

内存动态隔离

与cp u隔离方式类似,colocation agent会根据当前在线业务内存使用情况,动态扩缩混部大框的memory quota。 另外,通过调节oom_score_adj,混部任务的oom_sore被设为最大值,保证oom时混部任务尽量优先被驱逐。

网络带宽限制

我们使用了cni-adaptor组件,使得k8s node可以支持多种网络模式,对于转码混部任务,通常不需要被外部访问,因此通过annotation可以指定bridge网络模式,分配host-local的ip,避免占用全局网段中的ip资源。同时也利用了linux tc进行混部pod的网络带宽限制。

驱逐机制

混部agent层支持内存、磁盘、cpu load等维度的驱逐机制。当任意资源负载达到设置的驱逐水位时,agent会立即驱逐机器上的混部任务。为了防止任务在同一台机器上被频繁驱逐,需要在驱逐后设置一定的冷却时间,冷却期内禁止调度混部任务。

05 离线间混部

针对训练、转码等离线集群跑大数据混部任务的场景,我们基于在离线混部框架做了功能增强,其关键点在于yarn nodemanager on k8s。具体的调度步骤为:

B站云原生混部技术实践(B站云原生混部技术实践)(8)

  1. yarn node manager以daemonset的形式部署在相应的混部节点上
  2. 节点上的混部agent会动态检测在线容器负载变化,并根据设置的混部策略计算可混部值。这个值一方面会通过接口上报给yarn rm,另外一方面会设置到混部大框的cgroup中进行动态的资源限制
  3. 用户把大数据任务提交到混部集群时,rm会找到集群中有充足资源的混部节点,并最终在nm中拉起task

为了降低大数据任务对非混部业务的影响,大数据团队也做了相关技术改造,例如支持remote shuffle、基于应用画像识别小规格任务进行调度等。

06 混部管理平台

我们开发了界面化的混部管理平台来支撑日常的运维需求。主要功能包括:

B站云原生混部技术实践(B站云原生混部技术实践)(9)

B站云原生混部技术实践(B站云原生混部技术实践)(10)

07 混部效果

目前B站云平台大部分机器都参与了混部,混部机器的平均cpu使用率可以达到35%,峰值使用率则可以达到55%左右。这些混部算力支撑了B站大规模的视频转码任务,以及ai机审、大数据MR等任务,节省了数千台机器的采购成本。

08 总结

本文介绍了B站基于k8s云平台进行的混部实践,主要分为在离线混部、离线间混部等业务场景。我们采用了一套对k8s无侵入的混部框架,并且通过调度、资源隔离等手段来确保非混部业务的SLO,另外也开发了相关的监控、策略管理平台等来提高整体混部系统的可运维性。后续我们会在内核层隔离与可观测、统一调度等方面优化混部技术框架,持续助力云平台降本。

作者:许龙

来源: 哔哩哔哩技术

出处:https://mp.weixin.qq.com/s?__biz=Mzg3Njc0NTgwMg==&mid=2247488761&idx=1&sn=8170d8306741e92f200acbfbedbf98ea

,