今天咱们来讨论分布式资源调度。算法
咱们知道,计算机的出现很大程度上是为了分担人类的工做的。因此,整个计算机体系架构的演化的过程,都离不开对任务与资源这两个因素的考虑。如何利用最少的资源,运行最多的任务,且耗时最短,这是一直以来伴随咱们以及科学家的难题。对于单机系统来讲,从最先的单道程序设计技术、到多道程序设计技术、到如今的多核并行架构,解决方案正在逐步进化,也就是咱们最直观的感觉:计算机处理任务变快了。数据库
咱们能够类比一下操做系统的概念。相比于分布式资源调度,操做系统其实就是一种微观上的资源调度。咱们把任务与任务相关的一系列上下文(包括程序代码与数据),通通抽象为进程。进程就是任务。在单核CPU架构下,因为只有一个CPU核,因此咱们只能同时对一个任务进行处理。
可是,咱们的任务数量不仅会有1个,而是会远远超出CPU的数量,即“僧多粥少”的局面,因此,操做系统的进程调度算法出现了,好比时间片轮转调度算法,即一段时间内,CPU快速在多个任务之间快速切换、交替执行,故对每一个任务内部来讲,好像本身在独占CPU同样,这就是所谓的并发。除此以外,还有高优先级、高响应比、多级反馈队列调度等等任务调度算法,都在力图在单核CPU基础上解决这个问题。可是,咱们必定不会知足,为了追求更高程度的并发,即在同一时刻容许多个任务同时运行。因此,多核CPU就这样诞生了,即实现了所谓的并行。那么同理,分布式系统也一样须要这种资源与任务的调度机制,来协调资源与任务之间的关系。
分布式系统存在的意义之一,就是解决单体架构执行任务时的性能瓶颈,因此,咱们找来了一堆机器,来分担原来一台机器上的计算任务。可是,资源是多了,可是咱们要如何利用呢?这里面就涉及到资源如何公平公正的分给每个计算任务,让整个集群合理的利用硬件资源,短时、高效、公平的完成一系列的计算任务,而不至于某个任务被饿死或者撑死。因此,须要一个宏观上的“操做系统”,来合理的将无穷多个计算任务,分配到m个集群节点的计算资源上去执行。这,就是为何须要分布式资源调度机制。segmentfault
对于操做系统进程调度来讲,资源只有一份,那就是当前操做系统所在的计算机硬件资源;而任务有不少,资源:任务 = 1:N的关系,操做系统在进行任务调度以前,只须要收集它所在的计算机的硬件资源便可。而对于一个分布式系统中的集群,计算资源分布在多个节点上,任务仍是有不少,他们之间是M:N的关系。因此,分布式系统的工做稍微复杂些,它须要收集全部节点上的资源信息而非仅仅一个节点,而后对全部收集来的资源信息作一个统筹规划。服务器
若是让咱们本身设计一个调度系统,咱们天然会想到以前讲过的“分布式经典架构”中的集中式架构,由一个节点全权负责资源分配与任务调度。这,其实就是单体调度。单体调度模块称为“Scheduler”或“单体调度器”。全部的资源请求和任务调度都经过这个中心节点来进行。集中式调度器的常见模型,以下图所示。:
咱们看到,master节点会收集每一个节点的节点状态并交给master中的cluster state模块。这个节点状态就是指集群的计算资源的分布状况,而这个cluster state模块通常是一种内存数据库。而后,橙色方框Scheduling logic会到cluster state中查询集群资源的分布状况,而后根据分布状况执行本身的调度逻辑,进而将任务分配到各个节点上去执行。
咱们能够看到,单体调度器拥有全局资源视图和全局任务,能够很容易地实现对任务的约束并实施全局性的调度策略。目前不少集群管理系统采用了单体调度设计,好比Google Borg、Kubernetes等。Kubernetes的架构通过咱们以前的学习,相信你已经很熟悉了,下面咱们来介绍Borg的调度架构,因为Kubernetes吸取了许多Borg的先进理念,说不定你会在Kubernetes的架构中看到许多Borg的影子。下面咱们来以Borg为例,介绍一下它的单体调度实现。架构
Borg是谷歌内部的大规模集群管理系统。有了以前的理论基础,咱们直接上Borg的架构图:
咱们看到,Borg主要由BorgMaster与Borglet构成。BorgMaster是整个集群的大脑,Borglet表明集群中的节点在这里,咱们主要关注BorgMaster中的调度器Scheduler组件,它负责任务的调度,当用户提交一个做业给 BorgMaster 后,BorgMaster 会把该做业保存起来,并将这个做业的全部任务加入等待队列中。调度器异步地扫描等待队列,将任务分配到知足做业约束、且有足够资源的计算节点上。那么,Borg调度器是如何快速找到知足任务资源需求的那个机器呢?这个算法主要分为两个阶段:并发
首先看可行性检查阶段,这个很好理解。假如当前任务须要8G内存的资源,而某个机器的内存总数低于8G,那么这台机器则会被无情的过滤掉。框架
接下来就会进入到评分阶段,既然如今的全部机器已经符合要求了,是否是咱们随便找一台机器把任务分了就完事了呢?其实不是。咱们能够想一想,大概有以下两种方案:异步
第一种方案被称为“最差匹配算法“,第二种方案被称为”最佳匹配算法“。咱们分析一下这两种方案的优缺点:分布式
在单体调度架构中,中央服务器的性能会限制调度的效率,这个很好理解,但为何会限制支持的任务类型呢?
简单地说,这是由于不一样的服务具备不一样的特征,对调度框架和计算的要求都不同。好比说,你的业务最开始时只有批处理任务,后来发展到同时还包括流式计算任务。这两种计算任务的资源与调度需求各不相同,因此咱们的调度器须要适配每一种任务,为每个类型的任务设计不一样的资源分配与调度策略,因此单体调度框架会随着任务类型增长而变得愈来愈复杂,最终出现扩展瓶颈。
为了解决以上单体调度的问题,一种方法就是另起一层,分担中央服务器的任务,将任务调度与适配放到咱们刚才说的具体的二层调度器中,一层调度器再也不去适配每一种任务的资源与调度需求。也就是说,一层调度器只负责资源管理和分配,二层调度器负责任务与资源的匹配。这就是咱们所的两层调度架构。
总结一下,在两层调度中,中央调度器从总体上收集节点资源信息,并进行资源的管理与分配,将资源分配到第二层调度器;再由第二层调度器负责将资源与具体的任务配对。因此,第二层调度能够有多个调度器,以支持不一样的任务类型:
看到这里你们可能仍是不明白一层调度器这个资源分配,究竟是分配了什么。咱们用一个例子来详细讲解一下:oop
Mesos也是一个大型分布式集群资源管理框架。既然是资源管理,因此Mesos只负责集群底层资源的管理和分配,并不涉及任务调度与管理等功能。因此,Mesos若是要实现相似Borg那样的资源与任务管理,还须要上层框架的配合。
Mesos自己实现的调度器为第一层调度,负责资源管理,而后将第二层任务调度,交给框架完成。因此,Mesos是一个典型的两层调度架构:
这里咱们所说的二层调度的框架,是运行在Mesos上,是负责任务管理与调度的组件,好比 Hadoop、Spark等,每一个框架有他们本身的任务调度器,用于调度并完成不一样的任务,好比批处理任务、实时分析任务等。框架主要由调度器(Scheduler)和执行器(Executor)组成,调度器能够从 Master 节点获取集群节点的信息 ,执行器在Slave节点上执行任务。
在Mesos中,分配资源的过程叫作Resource Offer机制。Mesos Master主动将节点空闲资源,以相似发放Offer的方式发给每一个框架,若是框架须要则使用,不须要则还回。也就是说,经过 Resource Offer 机制,第一层调度器将资源主动分配给第二层调度器,而后第二层调度进行具体的任务匹配,从而实现了任务调度与资源管理的分离。
总结一下,Mesos Master经过资源分配算法决定给各个Framework提供多少资源,而Framework则决定接受哪些资源,以及哪些任务使用这些资源运行。这样一来,一个两层调度架构就实现了。
可是两层调度的一个问题是,因为第二层调度只能得到部分资源视图,并无单体调度掌控全局的能力。所以没法实现全局最优调度。为了解决这个问题,共享状态调度机制出现了。
为了解决单体调度的扩展瓶颈问题,以及两层调度只能得到部分资源视图的问题,咱们想,那么让两层调度器也可以看到全部节点的状态不就能够了,即咱们要一个地方来存储全部节点的状态就OK了。这,就是共享状态调度。
共享状态调度结合了单体调度掌控全局的特色,以及两层调度职责分离的优点。经过将单体调度器分解为多个调度器,且每一个调度器都有全局的资源状态信息,从而实现最优的任务调度,提供了更好的可扩展性。其架构以下:
Omega是Google的第二代集群管理系统,Omega 在设计时参考了 Borg 的设计,吸取了Borg 的优势,并改进了其不足之处。
Omega中以Cell为单位来管理集群,它是一个集群中的节点集合。好比集群中有10个节点,那么咱们能够把其中的2个节点称为一个Cell。在Omega中,因为须要共享每个Cell的资源状态,那么须要一个共享存储空间,来共享每一个Cell的状态。其架构图以下:
咱们看到,为了提升性能、而且能更方便的查到共享的集群状态数据,每一个Cell都会从中心的State Storage同步一份数据到每一个Cell内部。这样一来,Omega 就有效地解决了两层调度中 Framework 只拥有局部资源,没法实现全局最优的问题。
那么这几种资源调度方案字哪一种场景下使用更好呢?
最后咱们把讲过的三种调度方式作一个比较:
【分布式系统遨游】分布式计算
欢迎对本系列文章感兴趣的读者订阅咱们的公众号,关注博主下次不迷路~