关于Borg,Omega,Kubernetes,Mesos,Yarn的演绎已经很多。一般故事是这样的:Omega是Borg的下一代产品,着力解决Mesos/Yarn这样的调度器在设计中的缺点,但迄今并没有商用。Kubernetes曾经是承载了人们的希望来提供开源版的Omega调度器,然而过了一年半的时间,1.0都发布了,资源管理和调度功能仍然很弱,距离Omega更是为时尚早,反而Mesos倒是红红火火地用起来了。关于这些调度算法的概述,可以点击原文查看本公众号上一篇文章。
近日,专业Kubernetes和Docker咨询公司Kismatic采访了Omega论文的第一作者Malte Schwarzkopf,Malte详细解释了Omega的设计思路,以及他对目前集群操作系统资源管理的看法,并且提到了他目前在剑桥大学CamSaS项目中的核心工作Firmament(在上一篇公众号文章中也有提及),非常非常有见地,本文把这篇采访的主要问题和回答列在下边,供各位对分布式计算感兴趣的人士理解和参考。
1. Omega发表于2013年,Omega提出了共享状态的资源调度器设计,文章中提到的经验和教训今天是否还成立?
当然,集群编排发展非常快速,但Omega的核心理念在今天看来不仅没有过时,反而变得更加重要起来。2013年之前,在Google以外的公司验证和测试集群资源调度算法是非常困难的事情,但是这两年由于Mesos和Kubernetes的流行,这件事情要容易许多,因此,在2013年我们致力于解决的问题:如何更加有效地让不同类型的负载共享一个集群运行,如何让不同的团队开发他们自己的调度器并且能够看到整个集群的资源使用状态,这些问题已经为更多的人所意识和接受,人们逐步发现,集群上的不同负载,各自都需要不同的编排策略,不能简单粗暴地采用单一策略应用于全局。
2. 能解释一下为什么Omega的共享状态的调度器能够为异构环境下混合负载的计算集群提供更加灵活和有效的资源管理么?
我们考虑一个例子,一个单一的Hadoop集群,多个用户在上面运行MapReduce任务。这里只需要用一个非常简易的调度算法:所有的机器一共有
n个slots,调度器把slots分配给MapReduce任务,直到没有空余的slots为止。但是slot是一个非常粗粒度的调度单元,并不是所有的MapReduce任务都需要相同数量的资源,也不是所有的任务都会使用分配给它们的资源。实际上,有的工作并不包含MapReduce任务,因此相比静态的把机器资源划分成为slots,更好的理念是利用装箱任务来提高机器的使用率——当然,这个问题很复杂,它其实是一个NP完全问题,并且随着不同负载对资源装箱方式的不同,问题会更加复杂。例如:假如一个MapReduce任务运行在一台机器上,带宽已经占据了70%,那么你可能就不应当再把一个前端web服务器混排在这台机器上,因为过高的网络负载很有可能会影响这个web服务器的响应而导致大量"尾延迟"。
在Omega里,每个调度器都可以看到全局的资源,包括已有的任务和当前集群的状态(就是集群负载),然后基于此来做出调度决策。换句话,不同的调度器独立做出适合自己的调度策略,但跟所有的调度器共享信息。
3. 通常人们都假设Omega用来取代Borg,因为Borg已经快要达到伸缩性的上限了。你能澄清一些相关的看法么?
绝对不是这样的。在Omega论文之后,有许多研究工作都宣称集中式调度器不能适应大型集群,因此需要采用分布式调度架构。然而,开发Omega的主要原因并不是伸缩性,而是工程实现的灵活性。我们的目标是让不同的团队都可以来独立开发自己的调度器,这其实比伸缩性更加重要。事实上,一个实现良好的集中式调度器同样可以用于大型集群——Borg的论文也已经证明了这一点。
有一类问题是资源调度急待解决的,就是快速部署那些低延迟型的任务。Sparrow调度器是解决这个问题的优秀设计,但如果你的任务不是延迟敏感型的,或者吞吐量并没有超过每秒上万个任务,一个集中式调度器也可以工作得很好,甚至可以扩展到1万台机器以上。
4. 许多人对Mesos的出现感到激动。在Omega论文中,你指出Mesos的两层调度器存在一些跟信息隐藏相关的缺点,能否对此作进一步的解释?
首先,我是根据2012年Mesos的状态来写作Omega论文的。至今已经3年过去,因此我们当初指出的一些问题今天已经不存在了。
我们认为像Mesos这种单向授予资源的模型(Yarn也类似)有两个主要缺点:首先,调度器只能看到它分配的资源,然而分配好的资源交给应用级框架进行二次调度时,这些框架无法获知集群内其他框架的状态,因此,它无从获知集群内是否有更适合的资源,因此根据优先权实施抢占的功能就难以实现。当然,这个问题也是可以解决的,例如Mesos现在已经可以把运行低优先级任务的资源分配给高优先级任务,或者调度器的过滤器可以指定它们希望能够抢占资源,但是代价就是资源管理的API和逻辑变得更加复杂。
第二个缺点是资源囤积。有一些任务在运行之前要求获取所有资源,例如MPI就是这样,有状态的流处理框架也是如此(流处理的整个pipeline都需要
启动)。在两层调度框架模型如Mesos中就会引发一个问题:第二层的应用框架调度器可能会等待直到有足够资源,或者逐步积累小资源直到总量达到所需。如果是后种情况,那么就是资源囤积,因为这意味着在很长时间内这些资源没有得到利用。
最近我跟Mesos的核心开发人员Ben Hindman谈到了这些问题,他们告诉我正在计划一些激动人心的变化,包括调整单向资源分配的模型,使之能够支持并行资源分配和预订,可以用来解决上述问题。例如,Mesos将能够为多个调度器的资源分配提供乐观锁,回收部分二级调度器的资源,这种机制类似于Omega的冲突检测机制,从这一点来说,Mesos和Omega可以达到一致的状态——在集群中采用Mesos和Omega,调度器将拥有对集群资源的相同视图。
5. 在Omega论文中,你提到过Mesos这样的单向二级调度器已经证明并不适用于Google,能进一步解释一下么?
还是以前边的优先权抢占为例,在Google,终止低优先权的任务非常普遍,因为它们的资源需要分配给其他更重要的任务。事实上,在运行一个大型MapReduce任务的时候,我乐于看到整个任务执行期间,部分节点由于优先权抢占而任务失败然后被重新调度执行。因为Borg在调度时要么认为改MapReduce任务并不重要,或者该任务正在使用的部分资源被其他任务所需要,例如服务型任务(Gmail之类)。为了选择需要被抢占的任务,调度器必须能够看到它们,即使这些任务事实上是由二级调度器来管理的。例如Twitter的Heron流处理框架可能会抢占Hadoop或者Spark任务的资源,即使它们都属于不同的框架。另一个例子是我们在Omega论文中提到的,相比于给MapReduce静态地划分任务数,我们宁愿在低负载集群上动态增加任务。这种假设很合理,比如为什么我们要给MapReduce起100个worker?这只是人们手动输入的一个数字,调度器对于分配多少个worker有更多的背景知识。事实上,已经有一些其他系统也采取了类似的理念,比如微软的Apollo调度器已经支持乐观任务,学术研究系统Jockey和Quasar都展现了自动伸缩可以给系统设计带来巨大好处。不论调度器如何决策,它必须能够看到整个集群的状态,因此单向二级调度器并不适用于Google。
6. 在Omega论文中,你提到了Mesos的DRF(Dominant Resource Fairness)资源公平分配算法非常迅速,仅需1毫秒就可以给二级调度器分配相关资源。你能评价一下DRF算法,以及为什么Google采取了不同的手段么?
Google为什么没有采用DRF跟算法的复杂度和性能无关。仅仅是因为资源公平分配并不是Google所想要的。事实上,Google在分配资源是常常不公平,目的是为了让更多的任务可以快速执行,提升总体效率。当然,Google也会避免出现部分任务占据过多资源的情况,这是通过一个配额系统来工作的:采用虚拟现金来提供预算和"购买"资源,Borg论文在2.6节描述了这个配额系统是如何工作的。这给我们带来了一个关于"公平"的问题:你是愿意维持严格的公平,乃至部分资源可能空闲,还是愿意容许部分不公平,但可以让任务快速完成?——正确的选择应根据组织的负载而定,对于Google来说,后者更加适合。
7. 许多人因为不少公司包括Twitter,苹果等利用Mesos管理数据中心而而感到激动。尽管Omega论文的理念也很激动人心,但是在开源界有没有一些工作正在把Omega变成现实,例如Kubernetes,它是否正在朝着Omega的方向而演进?
Omega的确还没有在开源界变成现实,但是,Omega正在影响开源软件。第一个跟Omega有关的项目显然是Kubernetes,它的核心理念是用户应当向集群指定和提交状态,这跟Omega的要求很相似,因此,Kubernetes是一个构建Omega调度器的理想平台,事实上,Kubernetes的调度器是插件式的,因此在未来很可能可以支持多个不同的调度器,甚至是由使用者自己设计的调度器。
还有一些其他的工作吸取了Omega的设计理念,例如微软研究院设计的Mercury系统,能够支持不同类型的任务根据集群状态进行混排调度,他们的代码已经提交给了Yarn。
8. 因为Kubernetes的设计借鉴了Borg和Omega的原则,你认为类似Omega的共享状态调度器能够改善Kubernetes集群的灵活性和效率吗?
当然会。我最近看了Kubernetes和Mesos的代码,实话说,在调度器设计上相比Google在Borg和Omega上所做的工作还相当原始。然而,令人激动的地方在于插件式的调度API可以允许未来更加先进的调度器可以很方便地被采用,我们每个人都可以在这上面做一些激动人心的工作!
在剑桥大学,我和其他一些伙伴构建了一个完整的集群管理器——Firmament,方便进行我们的研究工作。我们在上面获得了一些出色的结果,而把这个工作通过插件嵌入Kubernetes,将使得我们的工作能够更加容易为世界所知。
9. 在你看来,集群调度器还有哪些挑战需要解决?下一个需要解决的困难是什么?
容器已经能够让不同的负载在异构集群上运行变得更加可行。有了Kubernetes或者其他容器编排系统(如Mesos,Tectonic,Docker Machine),我们
可以在同一个集群上运行完全不同的应用程序,因此人们将会逐渐更集中注意在如何更加聪明地调度上。到目前为止,人们在开源项目上所做的工作是让一切跑起来(这当然很不容易)——但我认为接下来是否拥有更好的调度器将是下一个要解决的障碍。
列举一下主要的技术挑战:
1) 避免混排干扰。这对于高负载应用极其重要,一个差的调度策略如果把一些批处理任务调度到某些特定资源(硬盘,网络等),可以让批处理的任务性能下降3倍。如果是低延迟类任务,这影响会更大——尽管容器技术可以做到部分的CPU和内存隔离,它们仍然共享了相当多的底层资源,因此,如果我们能够预测什么样的任务混排能够相互影响更小,就会对整个系统的表现起到极大的帮助。
2) 我们需要解决Google宣称的"resource reclamation",收回一些任务(或者容器)所预订但并没有使用的资源,Google在Borg中实现了该特性,我
认为这是导致Google集群高效率的秘密武器之一,目前还没有开源软件支持该特性。
3) 增加灵活性,允许调度器挂起容器,移动并自动伸缩部署。
4) 我们需要能够让用户很方便地指定他们想要的调度策略,而不是从头写一个调度器。
目前,我们正在Firmament项目中努力解决部分上面的挑战,例如,它的插件式代价模型可以很方便地指定调度策略,我们也开发了代价模型来避免混排干扰。我们同样也证明在一个大型集群(数万台机器)有可能针对一个特定调度策略快速做出最优决策(只需要几百微秒)。这些都是超级激动人心的结果,在未来,你将会更多地听到我谈论这些方面,然而,在把“Google的infrastructure带给所有人”这条路上,还有相当多的工作要进行,也需要更多的人和更多出色的idea!