在YARN中,资源分配过程可概括为以下7个步骤:

  • 步骤1 NodeManager通过周期性心跳汇报节点信息。
  • 步骤2 ResourceManager为NodeManager返回一个心跳应答,包括需释放的Container列表等信息。
  • 步骤3 ResourceManager收到来自NodeManager的信息后,会触发一个NODE_UPDATE事件。
  • 步骤4 ResourceScheduler收到NODE_UPDATE事件后,会按照一定的策略将该节点上的资源(步骤2中有释放的资源)分配各应用程序,并将分配结果放到一个内存数据结构中。
  • 步骤5 应用程序的ApplicationMaster向ResourceManager发送周期性的心跳,以领取最新分配的Container。
  • 步骤6 ResourceManager收到来自ApplicationMaster心跳信息后,为它分配的container将以心跳应答的形式返回给ApplicationMaster。
  • 步骤7 ApplicationMaster收到新分配的container列表后,会将这些Container进一步分配给它内部的各个任务。

image.png
资源调度器关注的是步骤4中采用的策略,即如何将节点上空闲的资源分配给各个应用程序,至于步骤7中的策略,则完全由用户应用程序自己决定。

6.3.4 资源抢占模型

队列设置最小资源量和最大资源量。
有任务时会保证最小资源量,当有队列空闲时,会将这些资源分配给其他队列使用。
当原来空闲的队列有新的任务提交时,会把共享出去的资源拿回来。通常会等待一段不确定的时间,但会有个超时时间,超过之后会强制回收。
【需要重点看看这个强制回收在哪里,如何实现的?为何有时候没有按照预期执行。】
这部分和调度器无关,看源码的时候可以看父类。

仅当启用的调度器实现了 PreemptableResourceScheduler接口,且参数yarn.resourcemanager.scheduler.monitor.enable 的值被置为true(默认值为false)时,ResourceManager才启用资源抢占功能。资源抢占是通过第三方策略触发的,这些策略通常被实现成一些插拔式的组件类(实现SchedulingEditPolicy接口),并通过参数yarn.resourcemanager.scheduler.monitor.policies指定(默认情况下,YARN提供了默认实现ProportionalCapacityPreemptionPolicy)。ResourceManager将依次遍历这些策略类,并由监控类SchedulingMonitor进一步封装它们,SchedulingMonitor将周期性调用策略类中的editSchedule()函数,以决定抢占哪些Container的资源。

在YARN中,资源抢占整个过程可概括为如下步骤:

  • 步骤1 SchedulingEditPolicy探测到需要抢占的资源,将需要抢占的资源通过事件DROP_RESERVATION和PREEMPT_CONTAINER发送给ResourceManager。
  • 步骤2 ResourceManager调用ResourceScheduler的dropContainerReservation和preempt-Container函数,标注待抢占的Container。
  • 步骤3 ResourceManager收到来自ApplicationMaster的心跳信息,并通过心跳应答将待释放的资源总量和待抢占Container列表发返回给它。ApplicationMaster收到该列表后,可选择如下操作:1)杀死这些Container。2)选择并杀死其他Container以凑够总量。3)不做任务处理,过段时间可能有Container自行释放资源或者由ResourceManager杀死Container。
  • 步骤4 SchedulingEditPolicy探测到一段时间内,ApplicationMaster未自行杀死约定的Container,则将这些Container封装到KILL_CONTAINER事件中发送给ResourceManager。
  • 步骤5 ResourceManager调用ResourceScheduler的killContainer函数,而Resource-Scheduler则标注这些待杀死的Container。
  • 步骤6 ResourceManager收到来自NodeManager的心跳信息,并通过心跳应答将待杀死的Container列表返回给它,NodeManager收到该列表后,将这些Container杀死,并通过心跳告知ResourceManager。
  • 步骤7 ResourceManager收到来自ApplicationMaster的心跳信息,并通过心跳应答将已经杀死的Container列表发送给它(可能ApplicationMaster早已通过内部通信机制知道了这些被杀死的Container)。

image.png
关于资源抢占的实现,通常涉及以下几个需认真考虑的问题:

  • 如何决定是否抢占某个队列的资源?
  • 如何使资源抢占代价最小?

问题2:如何使资源抢占代价最小?
资源抢占是通过杀死正在使用的资源Container实现的,由于这些Container已经处于运行状态,直接杀死Container 会导致已经完成的计算白白浪费。为了尽可能避免资源浪费,YARN优先选择优先级低的Container作为资源抢占对象,且不会立刻杀死Container,而是将释放资源的任务留给应用程序自己:ResourceManager将待杀死的Container列表发送给对应的ApplicationMaster,以期望它采取一定的机制自行释放这些Container占用的资源,比如先进行一些状态保存工作后,再将对应的Container杀死,以避免计算浪费,如果一段时间后,ApplicationMaster尚未主动杀死这些Container,则ResourceManager再强制杀死这些Container。