Yarn资源调度策略探讨

Yarn资源调度策略探讨

Posted by danfeng on October 3, 2018

YARN资源调度策略探讨:

YARN在硬件和计算框架之间提供了一个抽象层,用户可以方便的基于YARN编写自己的分布式计算框架,而不用关心硬件的细节。由此可以看出YARN的核心功能:资源抽象、资源管理(包括调度、使用、监控、隔离等等)。从某种程度上说YARN类似于云计算中的IaaS。YARN的资源抽象比较简单,只有两种资源:内存和CPU。而资源数量是管理员手动设置的,每个NM节点可以贡献一定数量的内存(MB)和CPU,由RM统一管理,不一定是真实的内存和CPU数。其中内存资源是比较关键的,直接决定任务能否成功。如果某个任务需要的内存过多,可能无法执行,或者OOM。CPU资源的限制比较弱,只限定了一台NM上能并发执行多少任务。如果并发的过多,执行的可能比较慢。因此了解YARN的资源调度策略对于分布式应用的开发和维护是很有必要的。 image

基础概念

 在正式介绍具体的调度策略前,我们先分析下YARN的资源调度涉及到的一些概念。

  • Container是RM分配资源的基本单位。每个Container包含特定数量的CPU资源和内存资源,用户的程序运行在Container中,有点类似虚拟机。RM负责接收用户的资源请求并分配Container,NM负责启动Container并监控资源使用。如果使用的资源(目前只有内存)超出Container的限制,相应进程会被NM杀掉。==可见Container这个概念不只用于资源分配,也用于资源隔离==。理论上来说不同Container之间不能互相影响。可惜现阶段YARN的隔离做的还不太好。Container的另一个特性是客户端可以要求只在特定节点上分配,这样用户的程序可以只在特定的节点上执行。这跟计算本地性有关。Container是有最大资源限制的。这是由RM端的参数yarn.scheduler.maximum-allocation-mb和yarn.scheduler.maximum-allocation-vcores决定的。
  • 调度器和任务队列。 在YARN中,调度器是一个可插拔的组件,主要包含FIFO,CapacityScheduler,FairScheduler。可以通过配置文件选择不同的调度器。在RM端,根据不同的调度器,所有的资源被分成一个或多个队列(queue),每个队列包含一定量的资源。用户的每个application,会被唯一的分配到一个队列中去执行。队列决定了用户能使用的资源上限。资源调度,就是决定将资源分配给哪个队列、哪个application的过程。
      • 事件驱动。YARN实现了一套基于状态机的事件驱动机制:很多对象内部有一个预先定义好的有限状态机,相应的事件会触发状态转换,状态转换的过程中触发预先定义的钩子,钩子执行的过程中又生成新的事件,继续状态转换。这种设计的好处是耦合小,但不太好理解。几个角色:
        • Dispatcher —— 用于分发事件,一般是异步的。内部用一个BlockingQueue暂存所有事件。
        • Event —— 事件类型。
        • Handler —— 事件的消费者。每个消费者只handle特定的事件,所有Handler要在Dspatcher上注册。 这个机制在YARN的各个模块中用的非常广泛,不只用于调度器。
  • pull-based模型.AM通过心跳向RM申请资源,但当次心跳申请的资源不能马上拿到,而是要再经过若干次心跳才能拿到。这就是pull-based模型。 AM通过RPC协议ApplicationMasterProtocol与RM通信。这个协议在服务端的实现会调用YarnScheduler的allocate方法(所有调度器都必须实现YarnScheduler接口)。allocate方法有两个作用:1.申请、释放资源;2.表示AM是否存活。超过一段时间AM没有调用这个方法,RM会认为AM挂掉并尝试重新提交。 allocate方法有3个参数:。调度器会暂存这个application的资源请求,同时取出上次心跳后新分配给这个application的container,包装为一个Allocation对象返回。如果上次要求的资源也还没分配,那返回的Allocation对象就不包含任何资源。 那真正分配container是什么时候?答案是NM的心跳时。当NM向RM发送心跳时,会触发一个NODE_UPDATE事件。schduler会handle这个事件尝试在这个node上分配container。里面有一系列判断,比如当前节点是否有足够资源、优先给哪个application分配资源。如果成功分配container,就加入一个List中,等待AM下次心跳来取。 这点跟以前的JobTracker比较像,也是TaskTracker各自去拉取任务。

常用的调度器

调度器主要解决两个核心诉求:1.如何划分队列。2.如何分配资源。(包括为队列分配资源和为单个application分配资源。)

  • FIFO scheduler
     最简单、也是默认的调度器。只有一个队列,所有用户共享。 资源分配的过程也非常简单,先到先得,所以很容易出现一个用户满集群所有资源的情况。可以设置ACL,但不能设置各个用户的优先级。 优点是简单好理解,缺点是无法控制每个用户的资源使用。弊端:很可能一个大任务独占资源,其他的资源需要不断的等待。也可能一堆小任务占用资源,大任务一直无法得到适当的资源,造成饥饿 一般不能用于生产环境中。
  • CapacityScheduler ==YARN中默认的资源调度,基于层级队列的方式完成任务调度可以理解成一个个的资源队列。这个资源队列是用户自己去分配的==
     在FIFO的基础上,增加多用户支持,最大化集群吞吐量和利用率。它基于一个很朴素的思想:每个用户都可以使用特定量的资源,但集群空闲时,也可以使用整个集群的资源。也就是说,单用户的情况下,和FIFO差不多。这种设计是为了提高整个集群的利用率,避免集群有资源但不能提交任务的情况. 举例分析:比如我大体上把整个集群分成了AB两个队列,A队列给A项目组的人来使用。B队列给B项目组来使用。但是A项目组下面又有两个方向,那么还可以继续分,比如专门做BI的和做实时分析的。那么队列的分配就可以参考下面的树形结构:
root
------a[60%]
      |---a.bi[40%]
      |---a.realtime[60%]
------b[40%]

a队列占用整个资源的60%,b队列占用整个资源的40%。a队列里面又分了两个子队列,一样也是2:3分配。虽然有了这样的资源分配,但是并不是说a提交了任务,它就只能使用60%的资源,那40%就空闲着。只要资源实在空闲状态,那么a就可以使用100%的资源。但是一旦b提交了任务,a就需要在释放资源后,把资源还给b队列,直到ab平衡在3:2的比例。粗粒度上资源是按照上面的方式进行,在每个队列的内部,还是按照FIFO的原则来分配资源的。
 capacity调度器具有以下的几个特性:

- 层次化的队列设计,这种层次化的队列设计保证了子队列可以使用父队列设置的全部资源。这样通过层次化的管理,更容易合理分配和限制资源的使用。
- 容量保证,队列上都会设置一个资源的占比,这样可以保证每个队列都不会占用整个集群的资源。
- 安全,每个队列又严格的访问控制。用户只能向自己的队列里面提交任务,而且不能修改或者访问其他队列的任务。
- 弹性分配,空闲的资源可以被分配给任何队列。当多个队列出现争用的时候,则会按照比例进行平衡。
- 多租户租用,通过队列的容量限制,多个用户就可以共享同一个集群,同事保证每个队列分配到自己的容量,提高利用率。
- 操作性,yarn支持动态修改调整容量、权限等的分配,可以在运行时直接修改。还提供给管理员界面,来显示当前的队列状况。管理员可以在运行时,添加一个队列;但是不能删除一个队列。管理员还可以在运行时暂停某个队列,这样可以保证当前的队列在执行过程中,集群不会接收其他的任务。如果一个队列被设置成了stopped,那么就不能向他或者子队列上提交任务了。
基于资源的调度,协调不同资源需求的应用程序,比如内存、CPU、磁盘等等。在ResourceManager中配置它要使用的调度器,配置方式是修改conf/yarn-site.xml,设置属性:yarn.resourcemanager.scheduler.classorg.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler      **不足**  ++某个用户的程序最多可以占用100%的资源,如果他一直不释放,其他用户只能等待,因为CapacityScheduler不支持抢占式调度,必须等上一个任务主动释放资源++
  • FairScheduler 优先保证“公平”,每个用户只有特定数量的资源可以用,不可能超出这个限制,即使集群整体很空闲。默认情况,公平调度器FairScheduler基于内存来安排公平调度策略。也可以配置为同时基于内存和CPU来进行调度.当只有一个单一应用作业运行时,这个应用可以独占整个集群。当其他应用作业提交到集群时,空出来的资源将分配给新的应用,最终所有的应用作业会平分集群资源。不像Hadoop的默认调度器,它只将任务构造一个应用队列,公平调度器会在不饿死长周期作业的同时,优先让短周期作业先运行完成。在一组用户中共享集群也是合理的。最终,公平调度策略可以和应用优先级结合起来工作,优先级是一组权重值,资源会按照这个权重比例来分配给每个应用.

image