首先,来看怎么构造一个org.apache.hadoop.yarn.client.api.YarnClient

class ClientHelper(conf: Configuration) extends Logging {
val yarnClient = YarnClient.createYarnClient
info("trying to connect to RM %s" format conf.get(YarnConfiguration.RM_ADDRESS, YarnConfiguration.DEFAULT_RM_ADDRESS))
yarnClient.init(conf);
yarnClient.start

  !!!这个client还有个start方法,看来它跟RM很谈得来。的确,它实现了service这个接口。 好吧,它是一个服务。在YarnJobFactory中,我们用yarn-site.xml构造了一个YarnConfiguration对象,现在用它来初始化YarnClient,因为我们至少需要RM在哪,对不?

下边分几部分看submitApplication方法的实现

第一次调用YarnClient - 获取信息

def submitApplication(packagePath: Path, memoryMb: Int, cpuCore: Int, cmds: List[String], env: Option[Map[String, String]], name: Option[String]): Option[ApplicationId] = {
val app = yarnClient.createApplication
val newAppResponse = app.getNewApplicationResponse
var mem = memoryMb
var cpu = cpuCore // If we are asking for memory more than the max allowed, shout out
if (mem > newAppResponse.getMaximumResourceCapability().getMemory()) {
throw new SamzaException("You're asking for more memory (%s) than is allowed by YARN: %s" format
(mem, newAppResponse.getMaximumResourceCapability().getMemory()))
} // If we are asking for cpu more than the max allowed, shout out
if (cpu > newAppResponse.getMaximumResourceCapability().getVirtualCores()) {
throw new SamzaException("You're asking for more CPU (%s) than is allowed by YARN: %s" format
(cpu, newAppResponse.getMaximumResourceCapability().getVirtualCores()))
} appId = Some(newAppResponse.getApplicationId)

  首先通过yarnClient的createApplication方法获取一个YarnClientApplication对象。这是对RM的第一次请求,那么这次请求能得到什么信息呢?

通过这次请求得到的YarnClientApplication对象有两个方法:

  1. getApplicationSubmissionContext() , 它返回一个 ApplicationSubmissionContext对象。“ApplicationSubmissionContext represents all of the information needed by the ResourceManager to launch the ApplicationMaster for an application.”
  2. getNewApplicationResponse(), 它返回一个GetNewApplicationResponse对象。

鉴于YarnClient的createApplication方法没有任何参数,而YarnClient本身的状态中由用户指定的部分只是YarnConfiguration的内容,因此这个createApplication方法并不会告诉YARN客户端对资源的需求,因此它返回的app对象只包含了yarn的RM本身的信息。

在获取了app这个对象之后,submitApplication方法通过

 val newAppResponse = app.getNewApplicationResponse

从中取出了newAppResponse这个对象,然后从中取出了当前YARN集群最多支持的内存和CPU数目(TODO:这个值是当前可用的资源的值,还是整体上最大资源值)。然后对比给AM申请的container想要的内存和CPU,如果超出了YARN支持的最大值,就抛出异常。

否则,就把从newAppResponse中获取的applicationId赋给appId。看来在第一次请求时,YARN就给分配了appId,只是这个appId,并不和资源关联。

第二调用YarnClient - 提交job

如果资源足够,AM就可以提交,那就开始填写AM运行需要的资源,具体来说就是组装ApplicationSubmissionContext类的一个对象

    name match {
case Some(name) => { appCtx.setApplicationName(name) }
case None => { appCtx.setApplicationName(appId.toString) }
} env match {
case Some(env) => {
containerCtx.setEnvironment(env)
info("set environment variables to %s for %s" format (env, appId.get))
}
case None => None
} // set the local package so that the containers and app master are provisioned with it
val packageUrl = ConverterUtils.getYarnUrlFromPath(packagePath)
val fileStatus = packagePath.getFileSystem(conf).getFileStatus(packagePath) packageResource.setResource(packageUrl)
info("set package url to %s for %s" format (packageUrl, appId.get))
packageResource.setSize(fileStatus.getLen)
info("set package size to %s for %s" format (fileStatus.getLen, appId.get))
packageResource.setTimestamp(fileStatus.getModificationTime)
packageResource.setType(LocalResourceType.ARCHIVE)
packageResource.setVisibility(LocalResourceVisibility.APPLICATION) resource.setMemory(mem)
info("set memory request to %s for %s" format (mem, appId.get))
resource.setVirtualCores(cpu)
info("set cpu core request to %s for %s" format (cpu, appId.get))
appCtx.setResource(resource)
containerCtx.setCommands(cmds.toList)
info("set command to %s for %s" format (cmds, appId.get))
containerCtx.setLocalResources(Collections.singletonMap("__package", packageResource))
appCtx.setApplicationId(appId.get)
info("set app ID to %s" format appId.get)
appCtx.setAMContainerSpec(containerCtx)
appCtx.setApplicationType(ClientHelper.applicationType)
info("submitting application request for %s" format appId.get)
yarnClient.submitApplication(appCtx)

 这段代码设置了一个ApplicationSubmissionContext对象,然后再用yarnClient把它提交。这样就提交了一个YARN job。 

这样YarnClient一共用了两次,初始一次请求,获取appID和YARN的资源上限的情况,第二次请求,真正提交job。

  这段代码让我有些疑惑。首先appCtx大致分为两部分,一部分是job的信息,比如application type和application ID,另一部分和AM有关。和AM有关的部分又可以分成两块: 1. cpu和内存的大小,这两个资源组装在Resource这个类的对象里,由setResource设置到 appCtx中 2:运行container所需的命令和文件、环量变量,这部分设置在一个ContainerLaunchContext对象中,然后这个对象再被调置在appCtx中。疑惑的地方在于:为什么AM所需的资源要分成两部分呢?cpu和内存本就该是container申请的一部分呀?

看看API里关于containerLaunchContext类的说明,就更不明白了

ContainerLaunchContext represents all of the information needed by the NodeManager to launch a container.

It includes details such as:

  • ContainerId of the container.
  • Resource allocated to the container.
  • User to whom the container is allocated.
  • Security tokens (if security is enabled).
  • LocalResource necessary for running the container such as binaries, jar, shared-objects, side-files etc.
  • Optional, application-specific binary service data.
  • Environment variables for the launched process.
  • Command to launch the container.

好吧,“Resource allocated to the container.”, 这一条ContainerLanchContext并没有体现,在它提供的方法中并不能设置Resource。这不是骗人吗?

而appCtx却有单独的一个setAMContainerSpec 方法来设置Resource。那么在申请运行task所需的container时,如果说明其所需的资源呢?看来一定不是用了这个ContainerLaunchContext对象。

两个不同的协议

Samza AM为task申请container的代码在SamzaAppMasterTaskManager这个类里

  protected def requestContainers(memMb: Int, cpuCores: Int, containers: Int) {
info("Requesting %d container(s) with %dmb of memory" format (containers, memMb))
val capability = Records.newRecord(classOf[Resource])
val priority = Records.newRecord(classOf[Priority])
priority.setPriority(0)
capability.setMemory(memMb)
capability.setVirtualCores(cpuCores)
(0 until containers).foreach(idx => amClient.addContainerRequest(new ContainerRequest(capability, null, null, priority)))
}

  这里的amClient就是org.apache.hadoop.yarn.client.api.async.AMRMClientAsync类的对象。它用来和RM联系,处理container相关的事情。当AM请求container时,它就不用submitApplication中为AM设置container资源所需的那套动作了,而是使用ContainerRequest这类。而且ContainerRequest的构造方法中

public ContainerRequest(Resource capability, String[] nodes, String[] racks, Priority priority, boolean relaxLocality)

使用了Resource做为参数。

可见为AM申请container和为task申请container走的过程的确不一样。毕竟,为AM的运行申请container是作为提交任务的一部分最终发现两个是使用的不同的协议。提交任务时,使用的是这个协议:

message ApplicationSubmissionContextProto {
optional ApplicationIdProto application_id = 1;
optional string application_name = 2 [default = "N/A"];
optional string queue = 3 [default = "default"];
optional PriorityProto priority = 4;
optional ContainerLaunchContextProto am_container_spec = 5;
optional bool cancel_tokens_when_complete = 6 [default = true];
optional bool unmanaged_am = 7 [default = false];
optional int32 maxAppAttempts = 8 [default = 0];
optional ResourceProto resource = 9;
optional string applicationType = 10 [default = "YARN"];
} message ContainerLaunchContextProto {
repeated StringLocalResourceMapProto localResources = 1;
optional bytes tokens = 2;
repeated StringBytesMapProto service_data = 3;
repeated StringStringMapProto environment = 4;
repeated string command = 5;
repeated ApplicationACLMapProto application_ACLs = 6;
}

ContainerLaunchContextProto里根本没有代表cpu和内存资源的ResourceProto,这个Protocol是在ApplicationSubmissionContextProto里。对照containerLaunchContext类的说明,的确显得很奇怪。

而申请container的请求,走的是

message ResourceRequestProto {
optional PriorityProto priority = 1;
optional string resource_name = 2;
optional ResourceProto capability = 3;
optional int32 num_containers = 4;
optional bool relax_locality = 5 [default = true];
} message ResourceProto {
optional int32 memory = 1;
optional int32 virtual_cores = 2;
}

Samza在YARN上的启动过程 =》 之二 submitApplication的更多相关文章

  1. Samza在YARN上的启动过程 =》 之一

    运行脚本,提交job 往YARN提交Samza job要使用run-job.sh这个脚本. samza-example/target/bin/run-job.sh  --config-factory= ...

  2. Linux运维面试题:请简要说明Linux系统在目标板上的启动过程?

    Linux运维面试题:请简要说明Linux系统在目标板上的启动过程? 该问题是Linux运维面试最常见的问题之一,问题答案如下: 1.用户打开PC的电源,BIOS开机自检,按BIOS中设置的启动设备( ...

  3. Spring Boot启动过程(二)

    书接上篇 该说refreshContext(context)了,首先是判断context是否是AbstractApplicationContext派生类的实例,之后调用了强转为AbstractAppl ...

  4. Android应用程序启动过程(二)分析

    本文依据Android6.0源码,从点击Launcher图标,直至解析到MainActivity#OnCreate()被调用. Launcher简析 Launcher也是个应用程序,不过是个特殊的应用 ...

  5. Tomcat启动过程(二):EndPoint解析

    EndPoint提供基础的网络IO服务,用来实现网络连接和控制,它是服务器对外I/O操作的接入点.主要任务是管理对外的socket连接,同时将建立好的socket连接交到合适的工作线程中去.里面两个主 ...

  6. Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动

    之前在Spring Boot启动过程(二)提到过createEmbeddedServletContainer创建了内嵌的Servlet容器,我用的是默认的Tomcat. private void cr ...

  7. Spring Boot启动过程(七):Connector初始化

    Connector实例的创建已经在Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动中提到了: Connector是LifecycleMBeanBase的子类,先是设置L ...

  8. Spring Boot启动过程(三)

    我已经很精简了,两篇(Spring Boot启动过程(一).pring Boot启动过程(二))依然没写完,接着来. refreshContext之后的方法是afterRefresh,这名字起的真.. ...

  9. Hadoop 系列文章(三) 配置部署启动YARN及在YARN上运行MapReduce程序

    这篇文章里我们将用配置 YARN,在 YARN 上运行 MapReduce. 1.修改 yarn-env.sh 环境变量里的 JAVA_HOME 路径 [bamboo@hadoop-senior ha ...

随机推荐

  1. Span flag详解

    在android中,如果要实现text的各种样式,图文混排等,简单的样式可以靠几个不同的textview来拼成,而复杂的样式要求,用不同的textview来拼接则不太现 实.这时候就spannable ...

  2. jQuery 日历控件 FullCalendar 初识

    最近有个日程管理的需求,就学习了一下 FullCalendar 控件的一些基本知识,本文不是详细介绍该控件的 API 的文档,而是记录本人使用过程中的一些学习情况. 先看一下效果图  月/周/日视图 ...

  3. UVALive 3027(并查集)

    题意:某公司的各企业群要建立联系,I i j 表示企业i与企业j建立联系,并且以企业j为中心(并查集中的父亲)(企业j为暂时的中心企业),E i 表示查询企业 i 距离此时的中心企业的距离.各企业间的 ...

  4. Windows服务器nginx+tomcat服务负载均衡

    一.安装两个tomcat服务自启动 1. 解压两个tomcat,名称为分别1,2 2. 配置环境变量 3. 修改文件server.xml中的三个端口号,使得两个tomcat不冲突 (1)<Ser ...

  5. C语言中格式化输出的转换说明的fldwidth和precision解析

    首先说什么是C语言的格式化输出,就是printf和它的几个变种(grep -E "v?(sn|s|f)printf").像这些函数都有一个参数format,format中可以加点转 ...

  6. 【Winform】 无法将类型为“System.Windows.Forms.SplitContainer”的对象强制转换为类型“System.ComponentModel.ISupportInitialize”。

    问题:将dotnet framework 4.0 切换到2.0时,编译没有问题,在运行时出现如下错误:System.InvalidCastException: 无法将类型为“System.Window ...

  7. 几个好用的截取字符串的php函数分享

    分享几个好用的PHP 截取字符串函数(支持gb2312和utf-8). 1.截取GB2312字符用的函数 <?php /** **截取中文字符串 * edit by www.jbxue.com ...

  8. 思道OA PK 通达OA 同场竞技 谁与争锋

    技术架构 思道OA 通达OA 开发语言 微软ASP.NET 4.0 PHP开源脚本语言 64位平台 64位 32位 数据库 SQL Server大数据库 MySQL开源数据库 官网下载 下载地址 下载 ...

  9. ajax中的post方法中回调函数不执行的问题

    前一段时间接触了JQuery Ajax中的.post()方法和.get()方法,感觉到ajax的简洁和强大,当用到.post()方法时,去W3上查找相关的使用方法,感觉十分简单,用法很明了,然后,直接 ...

  10. [Learn Android Studio 汉化教程]第四章 : Refactoring Code

    [Learn Android Studio 汉化教程]第四章 : Refactoring Code 第四章 Refactoring Code    重构代码 在Android Studio中开发,解决 ...