ApplicationMaster源码分析
ApplicationMaster源码分析
我们从sparksubmit的源码中发现,当创建rmclient之后,我们在nm中启动了一个java进程applicationmaster
val amClass =
if (isClusterMode) {
Utils.classForName("org.apache.spark.deploy.yarn.ApplicationMaster").getName
} else {
Utils.classForName("org.apache.spark.deploy.yarn.ExecutorLauncher").getName
}
然后,我们现在就开始,看看启动applicationmaster的时候发生了什么
def main(args: Array[String]): Unit = {
// 解析参数
// --class=》userClass =》 SparkPi()
val amArgs = new ApplicationMasterArguments(args)
//创建了一个ApplicationMaster对象
val yarnConf = new YarnConfiguration(SparkHadoopUtil.newConfiguration(sparkConf))
master = new ApplicationMaster(amArgs, sparkConf, yarnConf)
//调用ApplicationMaster对象的run方法
ugi.doAs(new PrivilegedExceptionAction[Unit]() {
override def run(): Unit = System.exit(master.run())
})
}
1.ApplicationMaster.run()
//如果是集群模式则runDriver() 如果是client模式则runExecutorLauncher()
if (isClusterMode) {
runDriver()
} else {
runExecutorLauncher()
}
2.runDriver()
-- userClassThread = startUserApplication()
//获取需要执行的程序的main方法,这里只sparkpi的main方法
-- userClassLoader.loadClass(args.userClass).getMethod("main",classOf[Array[String]])
//创建了一个用户线程
-- new Thread().start()
-- run()
//执行main方法 --wordcount 而我们spark程序都会去new一个sparkcontext() 好了上下文在这儿就被创建了
-- mainMethod.invoke(null, userArgs.toArray)
//但是在创建sparkcountext是异步的,我们下面的程序已经被阻塞了,所以sparkcountext创建时就会去唤醒下面被阻塞的线程
-- ApplicationMaster.sparkContextInitialized(sc)
-- super.postStartHook()
//创建好后就把用户线程阻塞,让主线程执行
-- waitBackendReady()
//阻塞,等待应用程序上下文被创建
-- val sc = ThreadUtils.awaitResult()
// 注册 在applicationMaster里创建了一个RM的client 然后向RM注册一个任务
-- registerAM(host, port, userConf, sc.ui.map(_.webUrl), appAttemptId)
-- client.register(host, port, yarnConf, _sparkConf, uiAddress, historyAddress)
-- private val client = new YarnRMClient()
// 资源管理
-- createAllocator(driverRef, userConf, rpcEnv, appAttemptId, distCacheConf)
//申请资源
-- allocator = client.createAllocator()
//资源分配
-- allocator.allocateResources()
// 轮询资源管理器。如果没有待处理的容器请求,这会兼作心跳。
--val allocateResponse = amClient.allocate(progressIndicator)
// 通过Response拿到容器列表
--val allocatedContainers = allocateResponse.getAllocatedContainers()
// 处理分配的容器 由于 YARN 分配协议的工作方式,某些健康的竞争条件可能导致 YARN 授予我们不再需要的容器。在这种情况下,我们释放它们。
--handleAllocatedContainers(allocatedContainers.asScala)
// 在分配的容器中启动执行程序
-- runAllocatedContainers()
// 根据需要的Executors去启动container ,这里就发现Executor 和 container是一一对应的,直到把需要的container循环创建完
--for (container <- containersToUse)
if (runningExecutors.size() < targetNumExecutors)
numExecutorsStarting.incrementAndGet()
if (launchContainers) {
launcherPool.execute(() => {
try {
new ExecutorRunnable(
Some(container)........
).run()
// 创建nmClient 去连接 Container所在的nm
-- nmClient = NMClient.createNMClient()
-- nmClient.init(conf)
-- nmClient.start()
// 启动容器
-- startContainer()
// 准备java指令 /bin/java org.apache.spark.executor.YarnCoarseGrainedExecutorBackend
-- prepareCommand()
// 在Container中执行Command
-- nmClient.startContainer(container.get, ctx)
// 恢复用户线程的执行
-- resumeDriver()
// 执行完了回到主程序
-- userClassThread.join()

浙公网安备 33010602011771号