YARN Container 启动流程分析

YARN Container 启动流程分析

本文档从代码出发,分析了 YARN 中 Container 启动的整个过程,希望给出这个过程的一个整体的概念。

文档分为两个部分:第一部分是全局,从头至尾地把 Container 启动的整个流程串联起来;第二部分是细节,简要分析了 Container 启动流程中涉及到的服务、接口和类。

注意:

  • 基于 hadoop-2.6.0 的代码
  • 只写了与 Container 启动相关的逻辑,并且还大量忽略了很多细节,目的是为了得到一个整体的概念。
  • 为了让分析更具体,采用了这样的具体场景:
    • App 使用原生的 distributedShell
    • 调度器使用 FifoScheduler

第一部分:Container 启动流程

ApplicationMaster的主要逻辑

AM 与 NM 通信

AM 与 NM 们通过 NMClientAsync 通信,后者需要调用方提供一个回调类,NM 会在合适的时机调用回调类中的方法来通知 AM 。回调类 被AM实现为 NMCallbackHandler ,其中最重要的两个函数是:

  • onContainerStarted() ,当 NM 新启动了 Containers 时,会调用改方法,把 Container 列表传给它。
  • onContainerStopped() ,当 NM 停止了一些 Containers 时,会调用改方法,把 Container 列表传给它。

AM 与 RM 通信

AM 与 RM 通过 AMRMClientAsync 通信。

首先,通过 AMRMClientAsync.registerApplicationMaster() 向 RM 注册自己。

然后 AM 开始提交对 Container 的需求,在申请到需要数量的Container之前,先调用 setupContainerAskForRM() 设置对 Container 的具体需求(优先级、资源等),然后调用 AMRMClientAsync.addContainerRequest() 把需求提交给 RM ,最终该方法会把需求存到一个集合(AMRMClient.ask)里面。

AMRMClientAsync 同样需要调用方提供一个回调类,AM 实现为 RMCallbackHandler 。这个回调类主要实现了两个方法:

  • onContainersAllocated(), 获得新申请的 Container ,创建一个新线程,设置 ContainerLaunchContext , 最终调用 NMClientAsync.startContainerAsync() 来启动 Container。
  • onContainersCompleted(), 检查已完成的 Container 的数量是否达到了需求,没有的话,继续添加需求。

AM 需要与 RM 进行心跳,对于使用了 AMRMClientAsync 的 AM (如 DistributedShell ),心跳是通过 AMRMClientAsync 的一个线程实现。最终调用了 AMRMClientImpl.allocate() ,其主要动作就是从 ask 集合中拿到 Container 需求,组装成一个 AllocateRequest ,再通过 RPC 调用 RM 的相关方法进行申请。

具体一点,是通过ApplicationMasterProtocol.allocate() ,用 「Google protocol Buffer」格式进行 RPC 调用。

AM的三个主流程

总结上面说的,AM 有三个主要流程与 Container 的创建密切相关,这两个流程并行:

  1. 提交需求,通过心跳,把需求发送给 RM;
  2. 获取Container,通过心跳,拿到申请好的 Container;
  3. 每申请到一个 Container ,与 NM 通信,启动这个Container;

分析清楚了这三个主流程,也就清楚了 YARN Container 的启动逻辑。

Application 与 ResourceManager 的心跳

再看 RM 这边,在 AM 向 RM 注册时,RM 最终会生成一个代表这个 APP 的实例,我们先不分析注册的具体过程,只要知道在我们的情景下,最终是生成了一个 FicaSchedulerApp 。

AM 与 RM 进行心跳,发送的信息中含有:

  • AM 告诉 RM 两个信息: a) 自己对Container的要求,b) 已经用完的待回收的Container列表。
  • RM 给 AM 的回应:a) 新申请的 Container,b) 已经完成的 Container 的状态。

ApplicationMasterService 是 RM 的一个组成部分。RM启动时,会初始化这个服务,并根据配置,把相应的调度器 YarnScheduler 传进来。它实现了 ApplicationMasterProtocol 接口,负责对来自 AM 的 RPC 请求进行回应。在我们的情景中, ApplicationMasterService.allocate() 方法会被调用,核心逻辑是:

  • 触发 RMappAttemptStatusupdateEvent 事件。
  • 调用 YarnScheduler.allocate() 方法,把执行的结果封装起来返回。YarnScheduler 是与调度器通信的接口。所以,最后调用的是具体调度器的 allocate() 方法。

我们使用的是 FIFO 调度器,FifoScheduler.allocate() 方法的主要做两件事情:

  • 调用 FicaSchedulerApp.updateResourceRequests() 更新 APP (指从调度器角度看的 APP) 的资源需求。
  • 通过 FicaSchedulerApp.pullNewlyAllocatedContainersAndNMTokens() 把 FicaSchedulerApp.newlyAllocatedContainers 这个 List 中的Container取出来,封装后返回。

FicaSchedulerApp.newlyAllocatedContainers 这个数据结构中存放的,正是最近申请到的 Container 。那么,这个 List 中的元素是怎么来的呢,这要从 NM 的心跳说起。

NodeManager 与 ResourceManager 的心跳

NM 需要和 RM 进行心跳,让 RM 更新自己的信息。心跳的信息包含:

  • Request(NM->RM) : NM 上所有 Container 的状态,
  • Response(RM->NM) : 已待删除和待清理的 Container 列表

NM 启动时会向 RM 注册自己,RM 生成对应的 RMNode 结构,代表这个 NM ,存放了这个 NM 的资源信息以及其他一些统计信息。

负责具体心跳的,在 NM 这边是 NodeStatusUpdater 服务,在 RM 那边则是 ResourceTrackerService 服务。心跳的信息包括这个 NM 的状态,其中所有 Container 的状态等。

心跳最终通过 RPC 调用到了 ResourceTrackerService.nodeHeartbeat() 。其核心逻辑就是触发一个 RMNodeStatusEvent(RMNodeEventType.STATUS_UPDATE) 事件,这个事件由 NM 注册时生成的 RMNode 处理。

RMNode 接收 RMNodeStatusEvent(RMNodeEventType.STATUS_UPDATE) 消息,更新自己的状态机,然后调用 StatusUpdateWhenHealthyTransition.transition ,该方法从参数中获得这个 NM 所有的 Container 的信息,根据其状态分成两组:a) 刚申请到还未使用的,b) 运行完毕需要回收的,这两组 Container 的信息存放在 RMNode 的一个队列中。接着,发出一个消息: NodeUpdateSchedulerEvent(SchedulerEventType.NODE_UPDATE) 。这个消息,由调度器处理。

ResourceManager 处理NODE_UPDATE消息

RM 接收到 NM 的心跳后,会发出一个 SchedulerEventType.NODE_UPDATE 的消息,改消息由调度器处理。FifoScheduler 接收到这个消息后,调用了 FifoScheduler.nodeUpdate() 方法。与 Container 申请相关的主要逻辑如下:

获取已申请到的

从 RMNode 中获取出那些「刚申请还未使用」的 Container (NM 与 RM 心跳是获得),发出消息:RMContainerEventType.LAUNCHED,该消息由 RMContainer 处理;

回收已完成的

从 RMNode 中获取出那些「已经使用完待回收」的 Container,进行回收(具体回收过程略);

申请新的

在这个 NM 上申请新的 Container:

  • 通过 FicaSchedulerApp.getResourceRequest() 拿到资源请求(ResourceRequest)
  • 计算可申请的资源,调用 FicaSchedulerApp.allocate(),根据传进来的参数,封装出一个 RMContainer 添加到 newlyAllocatedContainers 中。然后触发事件 RMContainerEventType.START。该事件之后会由 RMContainer 处理。
  • 调用 FicaSchedulerNode.allocateContainer()

RMContainer 对 RMContainerEventType 事件进行处理处理:

  • RMContai
  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值