YARN-client提交任务处理过程

Client向RM提交任务的过程大致分为七步,如下图:



1. Client向RM发出请求
2. RM返回一个ApplicationID作为回应
3. Client向RM回应Application Submission Context(ASC)。ASC包括ApplicationID、user、queue,以及其他一些启动AM相关的信息,除此之外,还有一个Container Launch Context(CLC),CLC包含了资源请求数(内存与CPU),job files,安全token,以及其他一些用以在一个node上启动AM的信息。任务一旦提交以后,client可以请求RM去杀死应用或查询应用的运行状态
4. 当RM接受到ASC后,它会调度一个合适的container来启动AM,这个container经常被称作为container 0。AM需要请求其他的container来运行任务,如果没有合适的container,AM就不能启动。当有合适的container时,RM发请求到合适的NM上,来启动AM。这时候,AM的PRC与监控的URL就已经建立了。
5. 当AM启动起来后,RM回应给AM集群的最小与最大资源等信息。这时AM必须决定如何使用那么当前可用的资源。YARN不像那些请求固定资源的scheduler,它能够根据集群的当前状态动态调整。
6. AM根据从RM那里得知的可使用的资源,它会请求一些一定数目的container。This request can be very specific,including containers with multiples of the resource minimum values (e.g., extra memory)。

7. RM将会根据调度策略,尽可能的满足AM申请的container。也就是会分配container给AM,然后这些container的node manager会与AM进行通信,AM会向这些container的node manager发送启动容器的必要配置。

同时,在一个job运行时,AM会向RM汇报心跳与进度信息,在这些心跳过程中,AM可能去申请或释放container。会当任务完成时,AM向RM发送一条任务结束信息然后退出。如下图所示:




接下来,用一个简单的例子来说明整个过程。

代码参考:https://github.com/trumanz/hadoop_the_definitive_guide/tree/master/ch04-yarn/yarnExample


YARN client编写

1.创建一个Application

YarnClientApplication app = yarnClient.createApplication();

createApplication()方法在hadoop源码中yarn project中的org.apache.hadoop.yarn.client.api.impl中YARNClientImpl.java实现。


2.设置Application的名字

app.getApplicationSubmissionContext().setApplicationName( "truman.ApplicationMaster");

getApplicationSubmissionContext()方法位于org.apache.hadoop.yarn.client.api中的YarnClientApplication.java中

setApplicationName()方法位于org.apache.hadoop.yarn.client.api中的ApplicationSubmissionContextPBImpl.java中


3.设置Application的内存和CPU需求以及优先级和queue信息,YARN中RM将根据这些信息来选择合适的container来启动APP master,这个container经常被称作为container 0。

 app.getApplicationSubmissionContext().setResource(Resource.newInstance(100, 1));
 app.getApplicationSubmissionContext().setPriority(Priority.newInstance(0));
 app.getApplicationSubmissionContext().setQueue("default");

 setResource(),setResource(),setQueue()这些方法都在org.apache.hadoop.yarn.client.api中的ApplicationSubmissionContextPBImpl.java中


4.设置ContainerLaunchContext,这一步,amContainer中包含了App Master执行所需要的资源文件,环境变量和启动命令,这里将资源文件上传到了HDFS,这样在Node Manager就可以通过HDFS取得这些文件。

app.getApplicationSubmissionContext().setAMContainerSpec(amContainer);

setAMContainerSpec()方法位于org.apache.hadoop.yarn.client.api中的ApplicationSubmissionContextPBImpl.java中。


5.提交应用给RM

    ApplicationId appId = yarnClient.submitApplication(app
                    .getApplicationSubmissionContext());

submitApplication()方法位于org.apache.hadoop.yarn.client.api.impl中YARNClientImpl.java中。

对于client的编写还是比较简单的,不需要维护状态,只需要提交相应的消息给RM就行。


YARN APP Master编写

这部分编写比较复杂,AM需要与RM和NM通信,交互。

通过RM,申请container,并接受RM的一些信息,如可用的container资源,结束container等。

通过NM,启动container,并接收NM的信息,如container的状态变化以及Node状态变化等。

1.创建一个AMRMClientAsync对象,负责与RM交互通信

amRMClient = AMRMClientAsync.createAMRMClientAsync( 1000, new RMCallbackHandler());
这里的RMCallbackHandler 是我们编写的继承自AMRMClientAsync.CallbackHandler 的一个类,其功能是处理由Resource Manager收到的消息,
       其需要实现的方法由如下
       public void onContainersCompleted(List<ContainerStatus> statuses);
          public void onContainersAllocated(List<Container> containers) ;
          public void onShutdownRequest() ;
          public void onNodesUpdated(List<NodeReport> updatedNodes) ;
          public void onError(Throwable e) ;


       这里不考虑异常的情况下,只写onContainersAllocated, onContainersCompleted 这两个既可以, 一个是当有新的Container 可以使用, 一个是Container 运行结束。
       在onContainersAllocated 我们需要编写 启动container 的代码,amNMClient.startContainerAsync(container, ctx); 这里的ctx 同Yarn Client 中第4步中的amContainer 是同一个类型, 即这个container 执行的一些资源,环境变量与命令等, 因为这是在回调函数中,为了保证时效性,这个操作最好放在线程池中异步操作。

       在onContainersCompleted 中,如果是失败的Container,我们需要重新申请并启动Container,(这一点有可能是YARN的 Fair Schedule 中会强制退出某些Container 以释放资源) 成功的将做记录既可以。


2.创建一个NMClientAsyncImpl对象,负责与NM交互通信

 amNMClient = new NMClientAsyncImpl(new NMCallbackHandler());
这里NMCallbackHandler 使我们需要编写的继承自NMClientAsync.CallbackHandler 的对象,其功能是处理由Node Manager 收到的消息
       public void onContainerStarted(ContainerId containerId,  Map<String, ByteBuffer> allServiceResponse);
          public void onContainerStatusReceived(ContainerId containerId,  ContainerStatus containerStatus);
          public void onContainerStopped(ContainerId containerId) ;
          public void onStartContainerError(ContainerId containerId, Throwable t);
          public void onGetContainerStatusError(ContainerId containerId,  Throwable t) ;
          public void onStopContainerError(ContainerId containerId, Throwable t);

      这里简单的不考虑异常的情况下,这些函数可以写一个空函数体,忽略掉处理。


3.将自己(AM)注册到RM上

 RegisterApplicationMasterResponse response = amRMClient
                    .registerApplicationMaster(NetUtils.getHostname(), -1, "");

该函数将自己注册到RM上,没有提供RPC port和trackURL。

该方法在org.apache.hadoop.yarn.client.api.impl的AMRMClientImpl.java中。


4.向RM申请container

ContainerRequest containerAsk = new ContainerRequest(
                         //100*10M + 1vcpu
                         Resource.newInstance(100, 1), null, null,
                         Priority.newInstance(0));
      amRMClient.addContainerRequest(containerAsk);

 这里一个containerAsk   表示申请一个 Container, 这里的对nodes和rasks 设置为NULL,猜测MapReduce应该由参数来尝试申请靠近HDFS block的container的。

addContainerRequest()方法在org.apache.hadoop.yarn.client.api.impl的AMRMClientImpl.java中。



5.等待container执行完毕,清除退出

  我的代码如下, 循环等待container 执行完毕,并上报执行结果

 void waitComplete() throws YarnException, IOException{
          while(numTotalContainers.get() != numCompletedConatiners.get()){
               try{
                    Thread.sleep(1000);
                    LOG.info("waitComplete" + 
                         ", numTotalContainers=" + numTotalContainers.get() +
                         ", numCompletedConatiners=" + numCompletedConatiners.get());
               } catch (InterruptedException ex){}
          }
          exeService.shutdown();
          amNMClient.stop();
          amRMClient.unregisterApplicationMaster(FinalApplicationStatus.SUCCEEDED, "dummy Message", null);
          amRMClient.stop();
     }


YARN Container Application

真正处理数据的是由APP master中amNMClient.startContainerAsync(container, ctx)提交的 Container application,也就是提交给具体的container执行的工作。然后这这个应用并不需要特殊编写,任何程序通过提交相应的运行信息都可以在这些Node中的某个Container 中执行, 所以这个程序可以是一个复杂的MapReduce  Task 或者 是一个简单的脚本。


总结:

YARN 提供了对cluster 资源管理 和 作业调度的功能。
编写一个应用运行在YARN 之上,比较复杂的是App Mstr 的编写,其需要维护container 的状态并能共做一些错误恢复,重启应用的操作。 比较简答的是Client的编写,只需要提交必须的信息既可以,不需要维护状态。 真正运行处理数据的是Container Application ,这个程序可以不需要针对YARN做代码编写。

posted on 2018-06-05 21:38  sichenzhao  阅读(869)  评论(0编辑  收藏  举报

导航