我们知道Task Attempt在创建完成之后,就会通过ContainerAllocator向ResourceManager申请分配Container资源。
一 概述
ContainerAllocator 负责与Resource Manager通信,为作业申请资源。作业的每一个资源可以描述为<优先级,主机名,容量,container数目>
比如:
<10, “node1”,“memory:1G”, 3>//优先级是一个正整数,优先级值越小,优先级越高
<10, “node2”, “memory:2G”, 10>
<2, “*”, “memory:1G”, 20> //*表示这样的资源可来自任意一个节点,即不考虑数据本地性
ContainerAllocator通过周期性通过心跳和RM通信,RM 每一次返回已经分配的container列表和完成的container列表信息
二 工作流程
当用户提交作业后,MRAppMaster就会初始化Job,并创建一系列Map Task &Reduce Task。 由于Reduce Task依赖于Map Task之间的结果,所以ReduceTask会延后调度。在ContainerAllocator中,当Map Task完成一定比例的数量后(mapreduce.job.reduce.slowstart.
Completedmaps指定,默认5%),且Reduce Task可允许占用的资源能够折合成整数个任务时,才会为Reduce Task申请资源,取决于yarn.app.mapreduce.am.job.reduce.rampup.limit指定。
Map Task & Reduce Task之间数据结构转移也是不一样的
Map Task
=> scheduled -> assigned -> completed
Reduce Task
=> pending -> scheduled -> assigned -> completed
pending: 表示等待ContainerAllocotor发送资源请求
scheduled: 表示已经将资源请求发送给RM,但还没有收到分配的资源
assigned: 是已经收到的RM分配的资源
completed: 已经完成
Reduce Task之所以会多一个pending,是因为根据Map Task情况调整Reduce Task状态(在pending和 scheduled互相转移)。或者说主要是为了防止MapTask饿死,因为YARN中不再有map slot和reduce slot概念,只有内存和CPU真实资源,需要由ApplicationMa
Ster控制资源的申请顺序,以防止可能产生的作业饿死
此外ContainerAllocator将所有任务分为三类:FailedMap, Map 和
Reduce,并分别赋予他们5,20,10的优先级,所以会优先分配failed map ,然后是reduce,最后是map
总体流程:
# 将所有Map Task资源需求一次性发给Resource Manager
# 如果达到了Reduce Task调度条件,则开始为Reduce Task申请资源
# 如果为了某个task申请到了资源,则取消其他重复资源的申请。(由于HDFS的数据通常有备份,默认是三个,对于一个任务而言,考虑到rack和any级别本地性,他可能会有7个资源请求:如下所示:
<20, “node1”, “memory:1G”, 1>
<20, “node2”, “memory:1G”, 1>
<20, “node3”, “memory:1G”, 1>
<20, “rack1”, “memory:1G”, 1>
<20, “rack2”, “memory:1G”, 1>
<20, “rack3”, “memory:1G”, 1>
<20, “*”, “memory:1G”, 1>
),一旦该任务获取到了其中一个,则取消其他6个资源请求
# 如果任务运行失败,则重新为该任务申请资源
# 如果一个任务运行速度过慢,则会为其额外申请资源以启动备份任务(如果启动了推测执行功能)
# 如果一个节点失败任务数过多,则会撤销该节点的所有的资源请求
# 最后任务分配到container之后,都会发送一个TaskAttemptContain
erAssignedEvent事件,交由TaskAttemptImpl的状态机ContainerAssign
edTransition处理,而其方法最终会构造ContainerRemoteLaunchEvent事件,交给NodeManager启动Container执行任务
三
RMContainerAllocator继承了AbstractService, 相当于是一个生命周期比较长的组件。针对申请container资源的请求,他采取双重生产-消费者模式。
第一重生产-消费模式:
通过handle方法,将ContainerAllocatorEvent放入到eventQueue队列中
消费者eventHandlingThread不断从eventQueue中take event
第二重生产-消费者模式:将事件按照任务类型(Map/Reduce)放入调度请求列表scheduleRequests ,pendingReduces中。
scheduleRequests是一个区分Map 和 Reduce任务会立即被调度的请求列表
pendingReduces: 只是存储等待被调度的Reduce任务请求列表,会根据YARN中的资源情况和Map任务完成情况确定是将事件移到scheduleRequests中还是从scheduleRequests移回Reduce任务调度请求至pendingReduces
消费者RMContainerAllocator的父类RMCommunicator中的心跳线程allocatorThread,它周期性调用heartbeat方法,从YARN中RM获取可用资源,然后消费scheduleRequests列表中的请求,进行容器分配