产品战略专家梁宁确认出席AICon北京站,分享AI时代下的商业逻辑与产品需求 了解详情
写点什么

Volcano 火山:容器与批量计算的碰撞

  • 2020-06-05
  • 本文字数:6543 字

    阅读完需:约 21 分钟

Volcano火山:容器与批量计算的碰撞

Kubernetes 是当前非常流行的容器编排框架,在其发展早期重点以微服务类应用为主


但随着 Kuberentes 的用户越来越多,更多的用户希望在 Kubernetes 上运行 BigData 和 AI 框架,如 Spark、TensorFlow 等以构建统一的容器平台。但在 Kubernetes 运行这些高性能应用时,Kubernetes 的默认调度器无法满足高性能应用的需求,例如:公平调度、优先级、队列等高级调度功能。由于 Kubernetes 的默认调度器是基于 Pod 进行调度,虽然在 1.17 中引入了调度框架,但仍无法满足高性能应用对作业级调度的需求。



容器批量计算平台 Volcano

针对云原生场景下的高性能应用场景,华为云容器团队推出了 Volcano 项目。Volcano 是基于 Kubernetes 构建的一个通用批量计算系统,它弥补了 Kubernetes 在“高性能应用”方面的不足,支持 TensorFlow、Spark、MindSpore 等多个领域框架,帮助用户通过 Kubernetes 构建统一的容器平台。Volcano 作为容器调度系统,不仅包括了作业调度,还包含了作业生命周期管理、多集群调度、命令行、数据管理、作业视图及硬件加速等功能。



而在调度方面,Volcano 又对场景进行了细分、归类,并提供了相关的方案及算法;同时也为这些功能提供了调度框架,方便用户对调度器进行扩展。对于分布式计算或是并行计算来说,根据场景和作业属性的不同,也可以对其进行细分;在 《并行计算导论》 中将并行计算大致分为三类:

简单的并行

简单的并行指多个子任务(tasks)之间没有通信也不需要同步,可以完全的并行的执行。比较著名的例子应该就属 MapReduce 了,它的两个阶段都属于这种类型:mapper 任务在执行时并不会彼此通信同步运行状态;另一个常见的例子是蒙特·卡罗方法 ,各个子任务在计算随机数时也无需彼此通信、同步。由于这种并行计算有比较广泛的应用,例如 数据处理、VatR 等,针对不同的场景也产生了不同的调度框架,例如 Hadoop、DataSynapse 和 Symphony。同时,由于子任务之间无需信息和同步,当其中某几个计算节点(workers)被驱逐后,虽然作业的执行时间可能会变长,但整个作业仍可以顺利完成;而当计算节点增加时,作业的执行时间一般都会缩短。因此,这种作业也常常被称作 Elastic Job。

复杂的并行

复杂的并行作业指多个子任务 (tasks) 之间需要同步信息来执行复杂的并行算法,单个子任务无法完成部分计算。最近比较有名的例子应该算是 Tensorflow 的 “ps-work 模式” 和 ring all-reduce 了,各个子任务之间需要大量的数据交换和信息同步,单独的子任务无法独立完成。正是由于作业的这种属性,对作业调度平台也提出了相应的调度要求,比如 gang-scheduling、作业拓扑等。由于子任务之间需要彼此通信,因此作业在启动后无法动态扩展子任务,在没有 checkpoint 的情况下,任一子任务失败或驱逐,整个作业都需要重启,这种作业也常常被称作 Batch Job,传统的 HPC 场景多属于这种类型的并行作业,针对这种场景的调度平台为 Slurm/PBS/SGE/HTCondor 等。

流水线并行

流水线并行是指作业的多个子任务之间存在依赖关系,但不需要前置任务完全结束后再开始后续的任务;比如 Hadoop 里有相应的研究:在 Map 没有完全结束的时候就部分开始 Reduce 阶段,从而提高任务的并行度,提高整体的运行性能。符合这种场景的应用相对来说比较少,一般都做为性能优化;因此没有针对这种场景的作业管理平台。需要区分一下工作流与流水线并行,工作流一般指作业之间的依赖关系,而流水线并行一般指作业内部多个任务之间的依赖。由于工作流中的作业差异比较大,很难提前开始后续步骤。


值得一提的是"二次调度"。由于简单并行的作业一般会有大量的子任务,而且每个子任务所需要的资源相对一致,子任务之间也没有通信和同步;使得资源的复用率相对比较高,因此二次调度在这种场景下能发挥比较大的作用;Hadoop 的 YARN,Symphony 的 EGO 都属于这种类型。但是在面对复杂并行的作业时,二次调度就显得有也吃力;复杂并行作业一般并没有太多的子任务,子任务之间还经常需要同时启动,子任务之间的通信拓扑也可能不同 (e.g. ps/worker, mpi),而且作业与作业之间对资源的需求差异较大,因此导致了资源的复用率较低。


虽然针对两种不同并行作业类型有不同的作业、资源管理平台,但是根本的目标都是为作业寻找最优的资源;因此,Volcano 一直以支持以多种类型的作业为目标进行设计。目前,Volcano 可以同时支持 Spark、TensorFlow 和 MPI 等多种类型的作业。

常见调度场景

组调度 (Gang-scheduling)

运行批处理作业(如 Tensorflow/MPI)时,必须协调作业的所有任务才能一起启动;否则,将不会启动任何任务。如果有足够的资源并行运行作业的所有任务,则该作业将正确执行; 但是,在大多数情况下,尤其是在 prem 环境中,情况并非如此。在最坏的情况下,由于死锁,所有作业都挂起。其中每个作业只成功启动了部分任务,并等待其余任务启动。

作业级的公平调度 (Job-based Fair-share)

当运行多个弹性作业(如流媒体)时,需要公平地为每个作业分配资源,以满足多个作业竞争附加资源时的 SLA/QoS 要求。在最坏的情况下,单个作业可能会启动大量的 pod 资源利用率低, 从而阻止其他作业由于资源不足而运行。为了避免分配过小(例如,为每个作业启动一个 Pod),弹性作业可以利用协同调度来定义应该启动的 Pod 的最小可用数量。 超过指定的最小可用量的任何 pod 都将公平地与其他作业共享集群资源。

队列 (Queue)

队列还广泛用于共享弹性工作负载和批处理工作负载的资源。队列的主要目的是:


  • 在不同的“租户”或资源池之间共享资源

  • 为不同的“租户”或资源池支持不同的调度策略或算法


这些功能可以通过层次队列进一步扩展,在层次队列中,项目被赋予额外的优先级,这将允许它们比队列中的其他项目“跳转”。在 kube 批处理中,队列被实现为集群范围的 CRD。 这允许将在不同命名空间中创建的作业放置在共享队列中。队列资源根据其队列配置(kube batch#590)按比例划分。当前不支持分层队列,但正在进行开发。


集群应该能够在不减慢任何操作的情况下处理队列中的大量作业。其他的 HPC 系统可以处理成百上千个作业的队列,并随着时间的推移缓慢地处理它们。如何与库伯内特斯达成这样的行为是一个悬而未决的问题。支持跨越多个集群的队列可能也很有用,在这种情况下,这是一个关于数据应该放在哪里以及 etcd 是否适合存储队列中的所有作业或 pod 的问题。

面向用户的, 跨队列的公平调度 (Namespace-based fair-share Cross Queue)

在队列中,每个作业在调度循环期间有几乎相等的调度机会,这意味着拥有更多作业的用户有更大的机会安排他们的作业,这对其他用户不公平。 例如,有一个队列包含少量资源,有 10 个 pod 属于 UserA,1000 个 pod 属于 UserB。在这种情况下,UserA 的 pod 被绑定到节点的概率较小。


为了平衡同一队列中用户之间的资源使用,需要更细粒度的策略。考虑到 Kubernetes 中的多用户模型,使用名称空间来区分不同的用户, 每个命名空间都将配置一个权重,作为控制其资源使用优先级的手段。

基于时间的公平调度 (Fairness over time)

对于批处理工作负载,通常不要求在某个时间点公平地分配资源,而是要求在长期内公平地分配资源。例如,如果有用户提交大作业,则允许用户(或特定队列)在一定时间内使用整个集群的一半, 这是可以接受的,但在下一轮调度(可能是作业完成后数小时)中,应惩罚此用户(或队列)而不是其他用户(或队列)。在 HTCondor 中可以看到如何实现这种行为的好例子。


面向作业的优先级调度 (Job-based priority)


Pod 优先级/抢占在 1.14 版本中被中断,它有助于确保高优先级的 pod 在低优先级的 pod 之前绑定。不过,在 job/podgroup 级别的优先级上仍有一些工作要做,例如高优先级 job/podgroup 应该尝试以较低优先级抢占整个 job/podgroup,而不是从不同 job/podgroup 抢占几个 pod。

抢占 (Preemption & Reclaim)

通过公平分享来支持借贷模型,一些作业/队列在空闲时会过度使用资源。但是,如果有任何进一步的资源请求,资源“所有者”将“收回”。 资源可以在队列或作业之间共享:回收用于队列之间的资源平衡,抢占用于作业之间的资源平衡。

预留与回填 (Reservation & Backfill)

当一个请求大量资源的“巨大”作业提交给 kubernetes 时,当有许多小作业在管道中时,该作业可能会饿死,并最终根据当前的调度策略/算法被杀死。为了避免饥饿, 应该有条件地为作业保留资源,例如超时。当资源被保留时,它们可能会处于空闲和未使用状态。为了提高资源利用率,调度程序将有条件地将“较小”作业回填到那些保留资源中。 保留和回填都是根据插件的反馈触发的:volcano 调度器提供了几个回调接口,供开发人员或用户决定哪些作业应该被填充或保留。

Volcano 调度框架

Volcano 调度器通过 作业级的调度多种插件机制 来支持多种作业;Volcano 的插件机制有效的支撑了针对不同场景算法的落地,从早期的 gang-scheduling/co-scheduling,到后来各个级别的公平调度。下图展示了 Volcano 调度器的总体架构:



Cache 缓存了集群中 Node 和 Pod 信息,并根据 PodGroup 的信息重新构建 Job (PodGroup) 和 Task (Pod) 的关系。由于在分布式系统中很难保证信息的同步,因此调度器经常以某一时间点的集群快照进行调度;并保证每个调度周期的决定是一致的。在每个调度周期中,Volcano 通过以下几个步骤派发作业:


  • 在每个调度周期都会创建一个 Session 对象,用来存储当前调度周期的所需的数据,例如,Cache 的一个快照。当前的调度器中仅创建了一个 Session,并由一个调度线程执行;后续将会根据需要创建多个 Session,并为每个 Session 分配一个线程进行调度;并由 Cache 来解决调度冲突。

  • 在每个调度周期中,会按顺序执行 OpenSession, 配置的多个动作(action)和 CloseSession。在 OpenSession 中用户可以注册自定义的插件,例如 gang、 drf,这些插件为 action 提供了相应算法;多个 action 根据配置顺序执行,调用注册的插件进行调度;最后,CloseSession 负责清理中间数据。


(1) action 是第一级插件,定义了调度周期内需要的各个动作;默认提供 enqueue、allocate、 preempt 和 backfill 四个 action。以 allocate 为例,它定义了调度中资源分配过程:根据 plugin 的 JobOrderFn 对作业进行排序,根据 NodeOrderFn 对节点进行排序,检测节点上的资源是否满足,满足作业的分配要求(JobReady)后提交分配决定。由于 action 也是基于插件机制,因此用户可以重新定义自己的分配动作,例如 基于图的调度算法 firmament。


(2) plugin 是第二级插件,定义了 action 需要的各个算法;以 drf 插件为例,为了根据 dominant resource 进行作业排序,drf 插件实现了 JobOrderFn 函数。JobOrderFn 函数根据 drf 计算每个作业的 share 值,share 值较低代表当前作业分配的资源较少,因此会为其优先分配资源;drf 插件还实现了 EventHandler 回调函数,当作业被分配或抢占资源后,调度器会通知 drf 插件来更新 share 值。


  • Cache 不仅提供了集群的快照,同时还提供了调度器与 kube-apiserver 的交互接口,调度器与 kube-apiserver 之间的通信也都通过 Cache 来完成,例如 Bind。


同时,为了支持上面这些场景,Volcano 的调度器还增加了多个 Pod 状态以提高调度的性能:


  • Pending: 当 Pod 被创建后就处于 Pending 状态,等待调度器对其进行调度;调度的主要目的也是为这些 Pending 的 Pod 寻找最优的资源

  • Allocated: 当 Pod 被分配空闲资源,但是还没有向 kube-apiserver 发送调度决策时,Pod 处于 Allocated 状态。 Allocated 状态仅存在于调度周期内部,用于记录 Pod 和资源分配情况。当作业满足启动条件时 (e.g. 满足 minMember),会向 kube-apiserver 提交调度决策。如果本轮调度周期内无法提交调度决策,由状态会回滚为 Pending 状态。

  • Pipelined: 该状态与 Allocated 状态相似,区别在于处于该状态的 Pod 分配到的资源为正在被释放的资源 (Releasing)。该状态主要用于等待被抢占的资源释放。该状态是调度周期中的状态,不会更新到 kube-apiserver 以减少通信,节省 kube-apiserver 的 qps。

  • Binding: 当作业满足启动条件时,调度器会向 kube-apiserver 提交调度决策,在 kube-apiserver 返回最终状态之前,Pod 一直处于 Binding 状态。该状态也保存在调度器的 Cache 之中,因此跨调度周期有效。

  • Bound: 当作业的调度决策在 kube-apiserver 确认后,该 Pod 即为 Bound 状态。

  • Releasing: Pod 等待被删除时即为 Releasing 状态。

  • Running, Failed, Succeeded, Unknown: 与 Pod 的现有含义一致。


状态之间根据不同的操作进行转换,见下图。



Pod 的这些状态为调度器提供了更多优化的可能。例如,当进行 Pod 驱逐时,驱逐在 Binding 和 Bound 状态的 Pod 要比较驱逐 Running 状态的 Pod 的代价要小 (思考:还有其它状态的 Pod 可以驱逐吗?);并且状态都是记录在 Volcano 调度内部,减少了与 kube-apiserver 的通信。但目前 Volcano 调度器仅使用了状态的部分功能,比如现在的 preemption/reclaim 仅会驱逐 Running 状态下的 Pod;这主要是由于分布式系统中很难做到完全的状态同步,在驱逐 Binding 和 Bound 状态的 Pod 会有很多的状态竞争。

Volcano 调度实现

Volcano 调度器在支持上面这些主要场景时,分别使用了 action 和 plugin 两级插件。总体来讲,带有动作属性的功能,一般需要引入 action 插件;带有选择 (包括排序) 属性的功能,一般使用 plugin 插件。因此,这些常见场景中,fair-sharing、queue、co-scheduling 都通过 plugin 机制来实现:都带有 选择 属性,比如“哪些作业应该被优先调度”;而 preemption、reclaim、backfill、reserve 则通过 action 机制来实现:都带有 动作 属性,比如“作业 A 抢占 作业 B”。这里需要注意的是,action 与 plugin 一定是一同工作的;fair-sharing 这些 plugin 是借助 allocate 发展作用,而 preemption 在创建新的 action 后,同样需要 plugin 来选择哪些作业应该被抢占。这里通过 job-based fairness (DRF) 和 preempt 两个功能的实现来介绍 action 和 plugin 两种插件机制的使用,其它功能类似:


  • Job-based Fairness (DRF): 目前的公平调度是基于 DRF,并通过 plugin 插件来实现。在 OpenSession 中会先计算每个作业的 dominant resource 和每个作业 share 的初始值;然后注册 JobOrderFn 回调函数,JobOrderFn 中接收两个作业对象,并根据对像的 dominant resource 的 share 值对作业进行排序;同时注册 EventHandler, 当 Pod 被分配或抢占资源时,drf 根据相应的作业及资源信息动态更新 share 值。

  • 其它插件的实现方案也基本相似,在 OpenSession 中注册相应的回调,例如 JobOrderFn, TaskOrderFn,调度器会根据回调函数的结果决定如何分配资源,并通过 EventHandler 来更新插件内的调度数。

  • Preemption: preempt 是在 allocate 之后的一个 action,它会为“高”优先级的 Pending 作业选取一个或多个“低”优先级的作业进行驱逐。由于抢占的动作与分配的动作不一致,因此新创建了 preempt action 来处理相应的逻辑;同时,在选取高低优先级的作业时,preempt action 还是依赖相应的 plugin 插件来实现。其它动作插件的实现方式也类似,即根据需要创建整体的流程;将带有 选择 属性的问题转换为算法插件。

未来发展

Volcano 源自华为云容器团队的批量计算解决方案,华为云容器批量计算解决方案基于 Serverless 架构,用户无需关心底层资源的日常维护,同时还面向 AI、基因测序、视频转码、图像渲染等场景,进行了业务封装,客户只需提供数据,即可直接进行计算,实现秒级资源获取、开箱即用,同时降低了基础设施、业务平台的运维成本。


在 2019 年宣布 Volcano 开源后,吸引了来自 AWS、OpenAI、腾讯、百度、爱奇艺、小红书、滴滴、Vivo、趣头条等多家公司的参与和贡献(参见用户列表);并且腾讯和百度分别在 KubeCon 等国际会议上介绍 Volcano 在 AI 场景的使用经验。目前,容器批量计算解决方案已经在社交资讯、基因测序、在线教育、视频、电商等行业广泛使用。


随着场景的不断丰富,Volcano 调度器也在不断添加新的算法及动作,例如 backfill 等。同时,相应的接口也在不断的完善,方便用户扩展并自定义相应的算法。


Volcano 社区:https://github.com/volcano-sh


2020-06-05 10:062651

评论

发布
暂无评论
发现更多内容

20个最佳实践提升Terraform工作流程|Part 2

SEAL安全

最佳实践 IaC terrafrom 企业号9月PK榜

Embeddig技术与应用 (1) :Embedding技术发展概述及Word2Vec

Baihai IDP

人工智能 深度学习 AI Embedding 白海科技

单日 5000 亿行 / 900G 数据接入,TDengine 3.0 在中国地震台网中心的大型应用

TDengine

tdengine 时序数据库

NineData SQL 窗口现已支持深色模式,让开发者长期用眼无忧!

NineData

程序员 SQL开发 NineData

矩阵起源荣获上海科技创新资金计划项目立项资助

MatrixOrigin

数据库 云原生 HTAP MatrixOrigin MatrixOne

昇腾AI开发者创享日暨昇腾AI创新大赛2023大连区域赛成功举办

彭飞

异常检测:探索数据深层次背后的奥秘《下篇》

汀丶人工智能

数据挖掘 机器学习 异常检测

敏捷在建设项目中的应用

ShineScrum捷行

敏捷在建设项目

开放原子开发者工作坊|大咖论开源项目的安全之道

开放原子开源基金会

火山引擎DataLeap推出两款大模型应用: 对话式检索与开发 打破代码语言屏障

字节跳动数据平台

数据中台 数据治理 数据安全 数据研发 企业号9月PK榜

集成开发环境(IDE)的用途?

小齐写代码

集成销售和收入计划,打造企业内部的协作共赢

智达方通

数据分析 智达方通 优化流程

矩阵起源荣获"2023大数据助力工业经济"年度创新产品

MatrixOrigin

数据库 云原生 HTAP MatrixOrigin MatrixOne

九章云极DataCanvas公司智算中心正式落地

九章云极DataCanvas

浅谈终端环境感知及在零信任下的应用

权说安全

2023年开放原子校源行(哈尔滨站)重磅来袭

开放原子开源基金会

HarmonyOS纳入教育部“智能基座”项目,联合头部高校共育鸿蒙人才

最新动态

校源行丨开放原子开源基金会赴黑龙江科技大学走访交流

开放原子开源基金会

构建资产数智化平台,为央国企资产保值增值保驾护航

用友BIP

资产管理

DBeaverUltimate mac(数据库管理软件) v23.2.1直装激活版

mac

windows 数据库管理工具 苹果mac DBeaver Ultimate

如何下载和安装 Eclipse?

小齐写代码

第2期 | 破局 全球项目、精智核算

用友BIP

项目管理

Volcano火山:容器与批量计算的碰撞_容器_华为云与计算_InfoQ精选文章