Spark On Yarn程序的启动流程和之前的那篇《Yarn初步了解》文章中的“应用程序的”开发流程是一样的。先在某个NodeManager(NM)节点上启动Application Master(AM),再由AM向ResourceManager(RM)申请资源创建Container,最后AM收到RM创建成功的消息后,由AM向RM发送请求启动这些Container,然后就可以在这些Container中运行任务了。
Spark - Yarn Client流程:
设置使用的资源分配算法,该算法会同时考虑CPU以及内存资源,让所有Application的“主要资源占比”资源尽可能的均等。
在之前的《SparkContext初始化流程》和《SparkOnYarn与StandAlone模式的区别》文章中曾经提起过Spark On Yarn Client模式下的启动流程。这里对与Yarn进行交互的地方再详细说明下:
核心在于SparkContex启动的时候初始化TaskScheduler以及YarnClientSchedulerBackend。前者用于task的调度,后者用于资源的申请,在Yarn模式下资源就是申请Container。流程图如下所示:
1.提交AM到RM并启动AM
看下YarnClientSchedulerBackend类中的client.submitApplication()方法。
AM启动时执行的是ApplicationMaster类中main()函数,然后会执行到run()方法:
if (isClusterMode) {
runDriver()
} else {
runExecutorLauncher()
}
因为分析的是Yarn Client模式,所以会走runExecutorLauncher()方法。
2.AM注册到RM并申请Container
来看下AM类中的runExecutorLauncher()方法:
先执行registerAM(hostname, -1, sparkConf, sparkConf.getOption("spark.driver.appUIAddress")),将AM注册到RM上。底层看起来像是基于PB协议通过请求的方式实现的。
再执行allocator.allocateResources()向RM申请Container并启动。
3.启动Container
allocateResources()通过amClient最终会调用到rmClient分配Container。
allocateResources()最后会调用handleAllocatedContainers(allocatedContainers.asScala)启动Container。
至此,使用的Container就启动起来了,可以开始运行任务了!
Yarn中的Container究竟是个啥:
个人理解Yarn上的Container是一个Java进程。看下Hadoop中的代码:
每个Container会建立一个本地目录,然后将程序文件以及资源文件下载到这个目录中。然后执行脚本启动Container进程。
之前介绍Yarn的时候说过,NM会启动一个专门的线程监控所有Container的内存使用情况,如果Container内存超过设置的上限,就会将Container Kill掉。
所以是NM管理分配给它的所有内存资源?再由NM再将这些资源分配给Container?后续有空再研究下…