三类集群管理系统

集群系统架构图 集群系统分类_Google


现在业界流行的集群管理系统有Borg、Kubernetes、Slurm、Apollo等。谷歌在对集群管理系统进行划分上分为三类,分别是:集中式、双层结构、共享状态。Google的第一代/第二代集群(资源)管理系统被称为Borg,后续有Kubernetes。第三代集群管理调度框架就是Omega。

中央式(Monolithic scheduler)

中央式调度器实质上就是一个单一的调度agent来负责所有请求,通常用在HPC(高性能计算)中。由于将资源的调度和作业的管理功能全部放到一个进程中完成,扩展性较差:首先,集群规模受限。其次,很难引入新的调度策略,比如之前仅支持MapReduce作业,现在要支持流式作业,而将流式作业的调度策略嵌入到中央式调度器中是一项很难的工作。
中央式单体调度优缺点:
优点

  • 单体调度器有所有节点的资源信息,而且任务也由单体调度器来分发,所以它拥有全局的视野,对整体资源的把控较为准确
  • 单体调度系统的状态同步比较容易且稳定,这是因为资源使用和任务执行的状态被统一管理,降低了状态同步和并发控制的难度。

缺点

  • 单体调度器承担任务过重,很容易达到单点瓶颈
  • 调度算法只能全部内置在核心调度器当中,因此调度框架的灵活性和策略的可扩展性不高。
  • 单体调度存在单点故障的可能性。

双层式(Two-level)

双层调度器采用“分层”思想,上层是一个非常轻量级的的中央式调度器,下层是具体某个应用程序的调度器,如Hadoop、Storm、Spark、MPI等。这样就可以减小“中心节点”的压力,由原来的一个“中心”,变成二层“中心”;而且同一个集群中多种应用接入,多种框架混部,有效提高分布式集群的利用率。但是,这种“二级调度”也有缺陷:各应用无法感知集群整体的使用状况,只能等待上层调度推送信息;再加上资源分配采用轮询,在分配过程使用“悲观锁”(即PCC,Pessimistic Concurrency Control,悲观并发访问控制方式),并发粒度小,响应稍慢,缺乏一种有效的竞争机制。
两层调度的一个问题是,由于第二层调度只能获得部分资源视图,并没有单体调度掌控全局的能力。因此无法实现全局最优调度。

共享状态式(Shared state)

为克服双层调度器的不足,Google提出了共享状态调度。这种调度器将双层调度器中的集中式资源调度模块简化为持久化的“共享数据”(状态)和针对这些数据的验证代码——这里的“共享数据”实际上就是整个集群的实时资源使用信息。共享状态调度器最典型的代表就是Google的Omega系统,它也可理解为改进版的“双层调度器”。通过将双层调度器中的“共享数据”进行全局持久化,任何应用都可以看到集群资源信息。而且资源申请采用“乐观锁”(即MVCC,Multi-Version Concurrency Control,多版本并发访问控制方式),优先级控制,大大提升并发性。

论文:Omega: flflexible, scalable schedulers for large compute clusters

需要解决的问题

论文首先分析了现有的集群调度系统,见上文三类集群调度系统。无论是集中式调度系统还是双层结构的调度系统,都会有一些问题,比如集中式调度系统中可能会出现的单点故障导致集群不可用;双层结构调度系统虽然支持水平扩展,但是其master节点仍然是集群进行大规模扩展的瓶颈,由于使用悲观锁导致并发量低,如果集群规模很大,那么对于某些请求将不能及时作出回应。
面对云计算场景下的复杂性(复杂性的一个重要驱动因素是硬件和工作负载的异质性,这在大型计算集群中很常见)。Omega提出了集群调度系统必须要解决的几个问题:

  • 划分调度工作:工作可以通过以下方式分散到调度程序中:(1)负载平衡,不受工作负载类型的影响;(2)为工作负载的不同部分设置专门的调度器;或者(3)两者的结合。一些系统使用多个作业队列来保存作业请求(例如,针对不同的优先级),但这并不影响调度并行性:我们更感兴趣的是分配多少调度程序来处理队列。
  • 资源选择:可以允许调度器从所有集群资源中进行选择,或者限制为一个子集以简化决策。前者增加了做出更好决策的机会,当需要将“挑剔的”作业放置到接近满的集群中时,或者当决策依赖于总体状态(如未使用资源的总量)时,非常重要。
  • 干预:如果调度器竞争资源,多个调度器可能试图同时声明相同的资源。悲观的方法通过确保一个特定的资源一次只对一个调度程序可用来避免这个问题;乐观的方法检测到冲突(希望很少发生),并撤销一个或多个冲突的声明。乐观方法增加了并行性,但如果冲突过于频繁地发生,则可能会增加浪费的调度工作。
  • 分配粒度:由于作业通常包含许多任务,调度器对于如何调度它们可以有不同的策略:一个极端是对作业中的任务进行原子的全有或全无的组调度,另一个极端是随着为任务找到资源而增量地放置任务。全有或全无的策略可以通过逐步获取资源并储存它们直到作业可以开始,而代价是在此期间浪费这些资源。

上述缺点:一些作业(例如MPI程序)可能需要组调度,但会不必要地延迟其他只需要一小部分请求资源就可以进行的作业(例如MapReduce作业)的启动。如果不提供回滚机制,增量资源获取可能导致死锁,而囤积会降低集群利用率,也可能导致死锁。

  • 整个集群范围的行为:一些行为跨越多个调度程序。例如,实现各种类型的公平,以及对工作的相对重要性达成一致,特别是如果一个调度器可以抢占其他人的任务。这些行为的严格执行可以通过集中控制来实现,但是也可以依赖紧急行为来接近所需的行为。限制调度器可以使用的优先级范围等技术可以提供所需行为的部分执行,并且可以事后审计集群范围策略的遵从性,以消除在调度器的关键代码路径中进行检查的需要。

对此,Omega提出了基于上述缺点的解决方案:

  • 使用共享状态机制:Omega有多个调度器,调度器共享使用所有的集群状态信息
  • 乐观无锁并发:调度器根据掌握的集群资源信息进行资源分配,将分配结果告知控制器,由控制器来负责决定调度的最终结果

现有集群负载情况

文中根据现有集群主要运行作业情况,将负载主要分为批处理作业和服务。文中列出了Google中三个集群的资源负载情况。集群A是一个中等规模的、相当繁忙的集群,而集群B是目前在谷歌上使用的较大集群之一,集群C是最近发布了调度器工作负载跟踪的集群。

集群系统架构图 集群系统分类_分布式_02


从上图可以看到,批处理任务占据任务数的绝大部分,但是使用的资源却很少;而相关的服务任务,虽然数量少,但是占用的资源多;另外从下图也可以看到,批处理作业运行的大多是短时任务,而服务大多都是长时任务。

集群系统架构图 集群系统分类_云计算_03


集群系统架构图 集群系统分类_集群系统架构图_04


因为批处理作业都很短,而且快速周转是很重要的,所以轻量级、低质量的放置方法就可以了。但是长时间运行的高优先级服务作业(其中20-40%的服务作业运行超过一个月)必须满足严格的可用性和性能目标,这意味着需要仔细地放置它们的任务,以最大限度地抵抗故障并提供良好的性能。对于集群如何综合考虑各种因素条件,是一个NP-hard问题。因此需要一种调度器架构,它可以容纳这两种类型的作业,灵活地支持特定于作业的策略,并且还可以扩展到不断增长的调度工作量。

两级调度

解决静态分区问题的一个明显方法是动态地调整每个调度器的资源分配,使用一个中心协调器来决定每个子集群可以拥有多少资源。许多系统都使用这种两级调度方法,包括Mesos和Hadoop-on-Demand (HOD)。
在Mesos中,集中式资源分配器动态划分集群,将资源分配给不同的调度器框架。资源以报价的形式分发给框架,其中只包含“可用”的资源——目前未使用的资源。分配器通过一次只向一个框架提供给定的资源来避免冲突,并试图通过选择其提供的顺序和大小来实现主导资源公平(DRF算法)。因为一次只有一个框架在检查一个资源,所以它在调度决策期间有效地持有该资源的锁。换句话说,并发控制是悲观的。
当任务时间较短且频繁放弃资源时,以及当任务大小相对于集群大小较小时,Mesos工作得最好。
虽然Mesos框架可以使用“过滤器”来描述它希望被提供的资源类型,但它不能访问整个集群状态的视图——只能访问提供给它的资源。因此,它不能支持抢占或需要访问整个集群状态的策略:框架根本不知道已经分配给其他调度器的资源。Mesos使用资源囤积来实现帮派调度,并可能因此导致死锁。
YARN似乎也是一个两级调度程序。在YARN中,来自每个作业应用程序主机的资源请求被发送到资源主机中的单个全局调度器,该调度器根据应用程序指定的约束在各种机器上分配资源。但是应用程序主程序提供的是作业管理服务,而不是调度,因此YARN实际上是一个单片调度器架构。

共享状态调度

Omega使用的替代方法是共享状态方法:我们授予每个调度器对整个集群的完全访问权,允许它们以自由竞争的方式竞争,并在更新集群状态时使用乐观并发控制来调解冲突。这立即消除了两级调度器方法的两个问题——由于悲观并发控制而导致的有限并行性,以及调度器框架中资源的有限可见性——但当乐观并发性假设不正确时,可能需要重做工作。探索这种权衡是本文的主要目的。
Omega中没有中央资源分配器;所有的资源分配决策都发生在调度程序中。我们维护集群中资源分配的一个有弹性的主副本,我们称之为单元状态。每个调度器都有一个私有的、本地的、经常更新的单元状态副本,用于调度决策。调度器可以看到单元的整个状态,并且可以完全自由地声明任何可用的集群资源,只要它具有适当的权限和优先级—甚至是其他调度器已经获得的权限和优先级。一旦调度程序做出放置决定,它就会在原子提交中更新单元格状态的共享副本。在发生冲突的情况下,这样的提交最多只能成功一次:实际上,从状态同步到提交尝试的时间就是一个事务。无论事务是否成功,调度器随后都会重新同步其单元状态的本地副本,并在必要时重新运行其调度算法并再次尝试。
Omega调度器完全并行操作,不需要等待其他调度器中的作业,并且没有调度器间的行阻塞头。为了防止冲突导致“饥饿”,Omega调度器通常选择使用增量事务,它接受除了冲突的更改之外的所有更改(即,事务提供原子性,但不提供独立性)。调度器可以使用全空事务来实现组调度:作业的所有任务一起调度,或者一个都不调度,调度器必须尝试重新调度整个作业。这有助于避免资源囤积,因为一旦有足够的资源可用且事务提交,群调度作业就可以抢占低优先级任务,并允许其他调度作业同时使用这些资源。
共享状态方法的性能可行性最终取决于事务失败的频率和这种失败的代价。

调度效率比较

集群系统架构图 集群系统分类_Google_05


文中给出了这么一张图,从图中可以看到对于集中式调度系统在单路径情况下,只要调度时间是快速的,调度器的繁忙程度就很低,但随着job的增加,调度器繁忙程度也是呈线性增长。另外在多路径下,可伸缩性仍然受到单个调度器处理能力的限制,如上图中中间两部分所示,因此需要进行并行处理。

对于Omega系统,Omega方法的平均作业等待时间与多路径单片方法相当(上图b),这表明冲突和干扰相对较少,调度器繁忙度图(图c)证实了这一点。

集群系统架构图 集群系统分类_分布式_06


最后,文中给出了集中式调度系统(单路径、多路径)、两层调度系统、共享状态调度系统,不同调度方案中批处理作业(右轴)和服务(左轴)对调度器繁忙程度(z轴)的影响,可以看到共享状态模式对于降低调度器繁忙程度有着明显的优势。

总结

Omega据说应用到了Google内部实际的业务场景,虽然没有开源的系统供大家研究,但Omega集群调度系统提到的两个主要方案已经应用到了Google的Borg上了,而不是去替代Borg。另外Omega 在其论文中提到的共享状态调度,也解决了mesos中framework无法了解全局资源状态从而没法做调度优化的缺点(还跟Mesos沟通了一波,放入未来的计划中)。
虽然没有开源的系统架构以及源码供大家研究,但是Google Omega的基于共享状态信息以及乐观并发锁的机制对于集群调度系统设计很有借鉴意义。