Peloton: Uber针对不同集群工作负载的统一资源调度器

0
Peloton: Uber针对不同集群工作负载的统一资源调度器

集群管理是技术公司之间的一种通用软件基础设施,它将一组物理主机的计算资源聚合到一个共享资源池中,增强计算能力,并允许灵活使用数据中心硬件。在Uber,集群管理为各种工作负载提供了一个抽象层。随着业务规模的不断扩大,集群资源的有效利用变得非常重要。

然而,我们的计算堆栈没有得到充分利用,因为有几个专门用于批处理、无状态和有状态用例的集群。此外,我们业务的动态性质意味着,由于节假日和其他活动,拼车需求会出现巨大波动。这些边缘情况导致我们为每个集群过度提供硬件,以处理峰值工作负载。依赖于专用集群还意味着我们不能在它们之间共享计算资源。在高峰期,一个集群可能急需资源,而其他集群可能有多余的资源。

为了更好地利用我们的资源,我们需要在一个单一的计算平台上共同定位这些工作负载。由此产生的效率将降低我们基础设施每次出行的技术成本,最终使我们的司机合作伙伴和依赖优步谋生或出行的乘客受益。

我们得到的解决方案是Peloton,这是一个统一的调度程序,旨在跨不同的工作负载管理资源,将我们不同的集群合并为一个统一的集群。Peloton通过一个共享平台支持Uber的所有工作负载,平衡资源使用,弹性共享资源,并帮助我们规划未来的容量需求。

计算集群工作负载

在Uber中使用的计算集群工作负载主要有四种类型:无状态、有状态、批处理和守护进程作业。

  • 无状态工作是没有持久状态的长时间运行的服务。
  • 有状态工作是长时间运行的服务,例如来自Cassandra、MySQL和Redis的服务,它们在本地磁盘上具有持久状态。
  • 批处理作业通常需要几分钟到几天的时间才能完成。数据分析、机器学习、地图和自动驾驶汽车相关处理的批处理作业种类繁多,这些作业都来自Hadoop、Spark和TensorFlow等软件。这些作业本质上是可抢占的,对由于集群资源短缺而产生的短期性能波动不太敏感。

  • 守护进程的工作是运行在每台主机上的基础架构组件的代理,如Apache Kafka、HAProxy、M3 Collector等。
图1:我们将集群工作负载分为四类,每一类都有自己的属性和资源*

需要统一的资源调度

计算集群对Uber的业务至关重要。它们使基础设施所有者更容易管理内部环境和云环境中的计算资源。集群是Uber微服务架构的基本构建块,为服务所有者提供了几个重要功能,如自修复、动态放置和滚动升级,以及支持我们的大数据工作负载。

在共享集群上共享不同的工作负载是提高集群利用率和降低总体集群成本的关键。下面,我们将概述一些示例,说明混合工作负载的共存如何在我们的集群中驱动利用率,并帮助我们更准确地计划集群配置:

  • 资源复用和任务抢占是提高集群资源利用率的关键。然而,抢占在线作业(例如通常对延迟敏感的无状态或有状态服务)的成本非常高。因此,为了防止这些对延迟敏感的作业被抢占,我们需要在同一个集群上共同定位低优先级和可抢占的批处理作业,从而使我们能够更好地利用过度使用的资源。
  • 随着优步的服务走向active - active架构,我们将在每个数据中心保留用于灾难恢复(DR)的容量。该容灾容量可用于批处理作业,直到发生数据中心故障转移。此外,共享具有混合工作负载的集群意味着我们不再需要为在线工作负载和批处理工作负载分别购买额外的DR容量。
  • 在万圣节或其他大型活动期间,优步的在线工作量会激增新年前夕.我们需要提前计划这些高流量事件的容量,这要求我们为在线作业和批处理作业分别购买硬件。在一年的其他时间里,这些额外的硬件没有得到充分利用,导致了额外的、不必要的技术成本。通过将两个工作负载放在同一个集群上,我们可以将批处理工作负载的容量借给在线工作负载,以应对这些峰值,而无需购买额外的硬件。
  • 不同的工作负载具有彼此补充的资源配置文件。例如,有状态服务或批处理作业可能是磁盘IO密集型的,但无状态服务通常使用很少的磁盘IO。有了这些概要文件,在同一个集群上将有状态服务与批处理作业放在一起更有意义。

意识到这些场景将使我们能够实现更高的操作效率,改进容量规划,并优化资源共享,显然我们需要将不同的工作负载共同定位到一个单一的共享计算平台上。统一的资源调度器使我们能够管理各种工作负载,尽可能有效地使用我们的资源。

交替集群调度程序

近年来,由于数据中心的规模不断扩大和Linux容器的广泛采用,大规模集群管理已经成为一个热门话题。有四个与我们工作相关的集群管理器:谷歌BorgKubernetesHadoop纱,Apache便/极光

集群调度程序架构

下面的图2比较了四种集群调度器体系结构,将它们分解为六个功能区域:任务执行、资源分配、任务抢占、任务放置、作业/任务生命周期和应用程序级工作流,例如MapReduce

图2:我们可以在六个功能领域比较四个主要集群调度器的体系结构。

Mesos中的资源分配分为两个部分:框架级别的粗粒度分配和作业级别的细粒度分配。便使用DRF将资源分配给框架,但将作业级别的分配委派给每个框架。

由于以下原因,这些现有的调度器都不能满足我们的需求:

  • Borg不是开源的解决方案,因此,我们不能使用它。
  • 是Hadoop的批处理调度器,不支持或非常有限地支持无状态、有状态和守护作业。
  • Kubernetes它无法扩展到优步所需要的大型集群,即10000多个集群,也不支持弹性资源共享。由于批处理作业的高流变性,它也不是批处理工作负载的理想调度器。
  • 便设计用于管理集群,而不是调度工作负载。它对框架的粗粒度资源分配对于我们的用例来说不是最优的,因为它不支持弹性资源共享,并且需要为每个工作负载构建调度程序。

所以,我们创建了Peloton一个在Mesos上运行的统一资源调度程序,以支持我们的工作负载。

Peloton概述

Peloton是建立在便,利用它来聚合来自不同主机的资源,并以码头工人容器。为了更有效地管理集群范围的资源并更快地做出全局调度决策,Peloton使用分层资源池来管理不同组织和团队之间的弹性资源。

下面的图3显示了Peloton与其他集群管理系统的架构对比:

图3:涵盖了作业生命周期、任务放置和任务抢占,Peloton比其他可用的集群调度器更好地满足了我们的需求。

对于Peloton,我们遵循Borg使用的方法,主要的区别是使用Mesos作为资源聚合和任务执行层。Borg使用自己的Borglet执行任务。Peloton采用了类似于Borg控制器作业或YARN应用程序主(减去作业和任务生命周期管理)的方法来扩展用户指定的应用程序。

体系结构

为了实现高可用性和可伸缩性,Peloton使用active-active体系结构,其中包含四种独立的守护进程类型:作业管理器、资源管理器、放置引擎和主机管理器。这些守护进程之间的交互被设计成依赖性最小化,只在一个方向上发生。所有四个守护进程都依赖于Apache动物园管理员用于服务发现和领导者选举。

下面的图4显示了构建在Mesos、Zookeeper和之上的Peloton的高级架构卡珊德拉

图4:Peloton采用了具有多个Mesos集群的active-active架构。

Peloton体系结构由以下组件组成:

  • Peloton UI是一个基于web的UI,用于管理Peloton中的作业、任务、卷和资源池。
  • Peloton CLI是Peloton的命令行界面,功能与基于web的界面类似。
  • Peloton API使用协议缓冲区作为接口定义语言和YARPC作为它的RPC运行时。Peloton UI、Peloton CLI和其他Peloton扩展都构建在相同的Peloton API之上。
  • 主机管理器从其他Peloton组件中抽象出Mesos细节。它通过Mesos注册便HTTP API
  • 资源管理器维护资源池层次结构,并定期计算每个资源池的资源授权,用于调度或抢占相应的任务。
  • 放置引擎通过考虑作业和任务约束以及主机属性,查找位置(即任务到主机的映射)。对于不同的作业类型,例如有状态服务和批处理作业,放置引擎可以是可插入的。
  • 作业管理器处理作业、任务和卷的生命周期。它还支持对长时间运行的服务的作业中的任务进行滚动升级。
  • 存储网关在不同的存储后端上提供了一个抽象层,这样我们就可以从一个存储后端迁移到另一个存储后端,而无需对Peloton本身进行重大更改。我们为Cassandra内置了一个默认后端,但可以将其扩展到其他后端。
  • 组成员管理一组Peloton主实例,并选择一个leader将其注册为Mesos框架并实例化一个资源管理器。

所有四个Peloton守护进程都具有使用active-active实例或leader-follower拓扑的高可用性保证。Peloton保证所有任务至少执行一次,即使在任何应用程序实例失败之后。对于无状态的Peloton守护进程(如作业管理器和放置引擎),其内置的重试机制可以容忍任何实例失败。

Peloton的可伸缩性有几个维度,包括集群的大小(主机数量)、运行的作业和任务的数量,以及调度决策和启动任务的最大吞吐量。Peloton的目标是支持大规模批处理作业,例如,数百万个活动任务、50,000个主机和每秒1,000个任务。作业管理器和安置引擎都可以通过添加更多实例进行扩展。对Job Manager的所有API请求都将由存储后端处理,这使得存储后端的可伸缩性对Peloton至关重要。Peloton资源管理器只有一个leader,但是它应该扩展到数百万个任务,因为这些任务是最小的,只有资源配置和任务约束。此外,资源管理器中的所有任务都位于内存中,因此它应该能够处理高吞吐量的任务入队列和出队列。

众所周知,Mesos在运行约200,000个具有极低流失率的长时间运行任务时,可扩展到约45,000个主机。然而,当我们扩展到更大的集群规模时,例如,50,000个主机和高度动态的批处理作业,由于主通道和单事件通道的集中化设计,Mesos可能成为系统的瓶颈。

在Peloton中,Mesos是所有主机的聚合器,允许系统管理来自多个Mesos集群的资源。因此,Peloton可以通过管理多个适合我们的工作负载配置文件的Mesos集群来进行扩展。为了让Peloton管理多个Mesos集群,它可以为每个Mesos集群提供一组主机管理器。下面的图5显示了一个通过分片主机管理器管理多个Mesos集群来扩展Peloton的示例:

图5。在大规模部署中,Peloton可以管理多个Mesos集群并跨集群调度作业。

弹性资源管理

Peloton的资源模型定义了如何在不同的用户和作业之间分配集群中的所有资源,以及不同的用户如何弹性地共享资源。在大规模生产数据中心中使用了两种主要的资源分配机制:基于优先级的配额和分层不等式公平

这种模式已被采用Borg而且极光集群管理系统。在这种方法中,资源按优先次序划分为两个配额:生产配额和非生产配额。生产配额的总容量不能超过集群的总容量。但是,在面对集群范围内的资源争用时,不能保证非生产配额。

在Peloton中,我们使用分层的最大最小公平来进行资源管理,这在本质上是弹性的。Max-min公平性是用于集群管理的最广泛的资源分配机制之一,因为它具有通用性和性能隔离功能。许多当前的集群调度器,如YARN、VMware DRS和DRF都提供了最大最小公平性。

通过在Uber使用这种方法,如下面的图6所示,集群中的所有资源被划分到不同的组织中,然后进一步细分到该组织中的不同团队:

图6:我们在Peloton中为资源管理实现了分层的最大最小公平,以在不同的组织之间共享资源。

每个组织都有固定的资源保证,工作优先级在该组织边界内强制执行。例如,如果一个组织没有高优先级的工作,它就会得到其他优先级相对较低的工作的资源保证。该模型非常适合未来的退款,并为每个组织在其资源边界内定义其工作负载提供了更大的灵活性。

资源池

Peloton中的资源池是集群中资源子集的逻辑抽象。集群中的所有资源都可以按照组织和团队的不同,划分为层次化的资源池。资源池可以包含层次化的子资源池,以进一步划分组织内的资源。在自然资源池中,资源池之间的资源共享是弹性的,需求高的资源池可以从其他资源池借用资源,如果他们不使用这些资源。

每个资源池都有不同的资源维度,例如cpu、内存、磁盘大小和gpu我们预计,如果Mesos支持更多类型的资源隔离(如磁盘IO),那么未来资源维度的数量将会增加。

如下面的图7所示,我们为Peloton资源池中的每个资源维度概述了四种基本资源控制:

  • 预订是资源池对资源的最小保证。所有池之间的累积资源预留不能大于集群的容量。
  • 限制是资源池在任何给定时间可以消耗的最大资源数。如果集群有空闲容量,每个资源池都可以扩展到超过预留的限制。
  • 分享当集群中有空闲容量时,资源池有权分配的相对权重。
  • 权利定义资源池当时可以使用的资源。该控制根据资源池或集群中的工作负载随时变化。
图7:Peloton为组织中的各个团队管理资源池,使用Reservation、Limit和Share作为控件。

在下面的图8中,图表展示了Peloton的弹性资源共享如何从一个资源池中借用资源,以满足Uber生产中的另一个资源池的需求:

图8:使用团队1和团队2的资源池之间的弹性资源共享,一个资源池可以从另一个资源池借用资源,如果它的需求超过了它的保证预留。

有两张图显示了Uber的两个资源池。如上图8所示,当团队1的资源池对给定服务的需求增加或批处理作业数量增加时,资源将从另一个团队的资源池中借用。在这些情况下,Team 1的分配增加到超出其承诺的预留(保证容量);但是,当其他资源池中的需求增加时,资源会返回到它们原来的资源池中。这可以通过抢占来实现,这将在下一节中解释。

资源池抢占

弹性资源池层次结构使我们能够在不同的组织之间共享资源。每个组织都有自己指定的资源和资源池,当其他组织的资源未得到充分利用时,它们可以将这些资源和资源池借给其他组织。

然而,共享资源的代价是在出借方需要资源时无法检索资源。通常,调度器利用静态配额来实现更严格的SLA保证,Kubernetes和Aurora就是这种情况。在Uber,我们选择在团队之间共享资源,并通过在Peloton中启用抢占来实现更严格的SLA。在Peloton中,抢占让我们从使用的资源超过分配分配的实体收回资源回到最初的出借方以满足其计算需求

Peloton使用两种类型的抢占:

  • Inter-resource池抢占:该机制实现了所有资源池的最大最小公平。它对资源应用抢占策略,从资源池中收回资源。池的管理员可以插入不同的抢占策略。
  • 抢占Intra-resource池:这种类型的抢占基于作业优先级强制资源池内的资源共享。每个资源池可以有多个用户,每个用户运行多个作业。如果一个用户占用了资源池的全部容量,那么其他用户可能必须等待这些作业完成后才能运行作业。这将导致卡在池中的作业错过SLA。在另一种情况下,低优先级作业正在运行,高优先级作业进入,要求调度器为高优先级作业腾出空间。资源池内抢占当资源池发生竞争时,资源池内优先级较低的任务将被抢占。

Peloton在Uber的用例

自2017年9月以来,Peloton一直在由跨越不同可用性分区的8000多台机器组成的集群上运行生产中的批处理工作负载。每个月,这些集群运行300万个作业和3 600万个集装箱。

Peloton的工作负载解决了Uber的多个用例,涵盖了从日常拼车业务到自动驾驶汽车开发等最先进的项目的方方面面。

Apache火花

Peloton有自己的Apache Spark驱动程序,类似于用于YARN、Mesos和Kubernetes的驱动程序。Spark驱动程序在Peloton中作为控制器作业运行,它向同一作业添加和删除执行程序。Spark的shuffle服务作为一个容器在所有主机上运行。在Uber,我们每个月在生产中运行数百万个Spark作业,使用Peloton作为资源调度程序,提高所有与地图、市场和数据分析相关的作业的效率。

图9:当Peloton运行Apache Spark作业时,它使用它的Spark驱动程序来调度、优先级和启动执行器任务。

TensorFlow

Peloton支持分布式TensorFlow帮派调度,HorovodUber的分布式TensorFlow、Keras和PyTorch框架。Peloton允许这些框架配置cpu和gpu在同一个集群上调度混合工作负载。对于这个项目,Peloton运行超过4000个gpu的非常大的集群,并安排深度学习作业。

图10:在Peloton使用Horovod运行分布式TensorFlow作业的示例中,Peloton可以使用Mesos运行所有任务,并为它们提供一种机制来发现彼此。

上面的图10显示了分布式TensorFlow作业是如何在Peloton上启动的,方法是使用组调度抢占,让它同时调度所有任务,同时为它们提供一种相互发现的方式。

我们重新运行了官方的TensorFlow基准测试修改为使用Horovod并将其性能与常规分布式TensorFlow进行了比较。如下面的图11所示,我们观察到在Peloton上扩展的能力有了很大的改进。我们不再浪费一半的GPU资源——事实上,我们同时使用了两者《盗梦空间》V3而且resnet - 101模型达到了88%的效率。换句话说,由于Peloton的存在,模型训练的速度大约是标准分布式TensorFlow的两倍。


图11:当我们增加NVIDIA Pascal gpu的数量时,Peloton展示了如何在运行修改为使用Horovod而不是标准分布式TensorFlow的TensorFlow时变得更高效,这两种情况都适用于Inception V3和ResNet-101 TensorFlow模型。

自主车辆的工作负载

我们的内部调度器运行10万个任务的非常大的批处理作业。Peloton之前,优步先进技术集团(ATG),我们负责开发自动驾驶汽车系统的团队,在调度器上运行所有的批处理工作负载,使用许多小的任务集群。Peloton将所有这些小集群合并为一个拥有约3,000台主机的大集群,并统一了来自不同团队的所有调度器工作负载的处理。

地图

Peloton为Uber的地图团队运行大量的批处理工作负载,比如Spark和分布式TensorFlow。Peloton跨越多个集群和数百万个容器为所有这些工作负载提供动力。Maps团队的工作负载对抢占和分层资源共享以及在同一集群上配置gpu和cpu有非常特定的需求。

市场

优步的市场团队运营着一个平台,为我们的拼车业务匹配司机和乘客,并决定动态定价。该团队使用Peloton运行其定价工作负载(主要是Spark作业),促进了低延迟和更快的集群吞吐量。

下一个步骤

在接下来的几个月里,我们计划构建Peloton对其他工作负载的支持,比如无状态和有状态工作负载。我们还在控制平面上工作,该平面将用于在Mesos上部署和编排Peloton,这个过程现在是使用部署脚本执行的。

我们还计划将Mesos工作负载迁移到Kubernetes使用Peloton,这将有助于Peloton在主要云服务中的采用,因为Kubernetes已经在该领域获得了广泛的支持。Peloton已经在其API中与Kubernetes共享了许多公共设计模式,并且能够满足更高的可伸缩性需求。除了Mesos代理之外,Peloton的当前设计对Mesos的依赖非常少,而Kubelet可以作为Peloton中的代理。在这种方法中,我们可以将Peloton建模为Kubernetes的一个更可伸缩的核心实现:

  • 提供一个Kubernetes兼容的API在Peloton的核心API之上。
  • 添加一个支持Kubelets的新的Peloton主机管理器实现。
  • 现有的系统,例如米开朗基罗Uber的机器学习平台,仍然可以使用原生的Peloton核心API。
图12:我们可以使用Peloton将Mesos工作负载迁移到Kubernetes,使其对云更加友好。

如果您对建设大型基础设施感兴趣,请考虑一下申请我们团队的一个职位

订阅我们的通讯以跟上优步工程的最新创新。

* Apache Hadoop、Cassandra、Spark和Kafka标志是Apache软件基金会在美国和/或其他国家的注册商标或商标。使用这些标志并不意味着Apache软件基金会的认可。TensorFlow和TensorFlow标志是谷歌Inc.的商标。Redis是Redis Labs Ltd的商标。其中的任何权利均归Redis Labs Ltd所有。Uber Technologies的任何使用仅用于参考目的,并不表示Redis和Uber Technologies之间的任何赞助、背书或关联。

Min Cai是Uber计算平台团队的高级员工工程师,主要从事双活数据中心和集群管理工作。在加入Uber之前,他是VMware的高级员工工程师,负责虚拟机动态迁移(vMotion)和虚拟基础设施管理(vCenter)。他在期刊和会议上发表了20多篇论文,并拥有6项美国专利。

Mayank Bansal目前是Uber的一名员工工程师。的计算基础设施团队。在此之前,他致力于扩大优步的数据基础设施。他是Apache Hadoop的提交者,也是项目管理委员会的成员,也是Apache Oozie的提交者。

评论

没有可显示的帖子