首页 理论教育 应用程序部署源代码解析

应用程序部署源代码解析

时间:2023-06-29 理论教育 版权反馈
【摘要】:通过Main类的简单解析,可以将前面的脚本分析结果与后面即将进行分析的SparkSub-mit类关联起来,以便进一步解析与应用程序提交相关的其他源代码。被SparkSubmit透明化的部署模式定义的源代码如下。SparkSubmit支持SparkSubmitAction包含的3种行为,下面以行为SparkSubmitAction.SUBMIT为例进行分析,其他行为也可以从各自的具体处理代码进行分析。对应处理SparkSubmitAction.SUBMIT行为的代码入口点为submit,进入该方法,即进入提交应用程序的处理方法的具体代码如下。

应用程序部署源代码解析

本节从应用部署的角度解析相关的源代码,主要包括脚本提交时对应JVM进程启动的主类org.apache.spark.launcher.Main、定义应用程序提交的行为类型的类org.apache.spark. deploy.SparkSubmitAction、应用程序封装底层集群管理器和部署模式的类org.apache.spark. deploy.SparkSubmit,以及代表一个应用程序的驱动程序的类org.apache.spark.SparkContext。

1.Main解析

从前面的脚本分析可以得出,最终都是通过org.apache.spark.launcher.Main类(下面简称Main类)来启动应用程序的,因此,首先来分析Main类。

在Main类的源代码中,类的注释如下。

978-7-111-55442-4-Chapter03-15.jpg

对应在Main对象的入口方法main上的注释如下。

978-7-111-55442-4-Chapter03-16.jpg

Main类主要有两种工作模式,分别描述如下。

(1)spark-submit

启动器要启动的类为"org.apache.spark.deploy.SparkSubmit"时,对应为"spark-sub-mit"工作模式。此时,使用SparkSubmitCommandBuilder类来构建启动命令。

(2)spark-class

启动器要启动的类是除SparkSubmit之外的其他类时,对应为"spark-class"工作模式。此时,使用SparkClassCommandBuilder类的buildCommand方法来构建启动命令。

以"spark-submit"工作模式为例,对应的在构建启动命令的SparkSubmitCommandBuilder类中,上述调用的SparkClassCommandBuilder构造函数定义如下。

978-7-111-55442-4-Chapter03-17.jpg

978-7-111-55442-4-Chapter03-18.jpg

从这里初步的参数解析可以看出,前面脚本中的参数与最终对应的主资源间的对应关系如表3-1所示。

表3-1 脚本中的参数与主资源间的对应关系

978-7-111-55442-4-Chapter03-19.jpg

如果继续跟踪appResource赋值的源代码,可以跟踪到一些特殊类的类名与最终对应的主资源间的对应关系,部分如表3-2所示。

表3-2 特殊类的类名与主资源间的对应关系

978-7-111-55442-4-Chapter03-20.jpg

有兴趣的话可以继续跟踪SparkClassCommandBuilder类的buildCommand方法的源代码,查看构建的命令具体有哪些。

通过Main类的简单解析,可以将前面的脚本分析结果与后面即将进行分析的SparkSub-mit类关联起来,以便进一步解析与应用程序提交相关的其他源代码。

从前面的脚本分析可以看到,在提交应用程序时,Main所启动的类,也就是用户最终提交执行的类是org.apache.spark.deploy.SparkSubmit。因此下面开始解析SparkSubmit相关的源代码,包括提交行为的定义、提交时的参数解析,以及最终提交运行的代码解析。

2.SparkSubmitAction解析

SparkSubmitAction定义了提交应用程序的行为类型,源代码如下。

978-7-111-55442-4-Chapter03-21.jpg

从源代码中可以看到,分别定义了SUBMIT、KILL和REQUEST STATUS这3种行为类型,对应提交应用、停止应用和查询应用的状态。

3.SparkSubmit解析

SparkSubmit的全路径为org.apache.spark.deploy.SparkSubmit。从SparkSubmit类的注释可以看出,SparkSubmit是启动一个Spark应用程序的主入口点,这与前面从脚本分析得到的结论是一致的。首先来看SparkSubmit类的注释,如下所示。

978-7-111-55442-4-Chapter03-22.jpg

SparkSubmit会帮助用户设置Spark相关依赖包的classpath设置,同时,为了帮助用户简化提交应用程序的复杂性,SparkSubmit提供了一个抽象层,封装了底层复杂的集群管理器与部署模式的各种差异点。即,通过SparkSubmit的封装,集群管理器与部署模式对用户而言是透明的。

SparkSubmit透明化(通过SparkSubmit的封装,集群管理器与部署模式对用户而言是透明的)的集群管理器定义的源代码如下。

978-7-111-55442-4-Chapter03-23.jpg

被SparkSubmit透明化的部署模式定义的源代码如下。

978-7-111-55442-4-Chapter03-24.jpg

作为提交应用程序的入口点,SparkSubmit中根据具体的集群管理器进行参数转换、参数校验等操作,比如对模式的检查,代码中给出了针对特定情况下不支持的集群管理器与部署模式,在这些模式下提交应用程序会直接报错退出。

978-7-111-55442-4-Chapter03-25.jpg

首先,一个程序运行的入口点对应单例对象的main函数,因此在执行SparkSubmit时,对应的入口点是objectSparkSubmit的main函数,具体代码如下。

978-7-111-55442-4-Chapter03-26.jpg

其中,第3行代码中的SparkSubmitArguments类对应用户调用提交脚本spark-submit时传入的参数信息。对应的脚本的帮助信息(./bin/spark-submit--help)也是由该类的printUsageAndExit方法提供的。

找到上面的入口点代码之后,就可以开始分析其内部的源代码。对应参数信息的Spark-SubmitArguments可以参考脚本的帮助信息来查看具体参数所对应的含义。参数分析之后,便是各种提交行为的具体处理。SparkSubmit支持SparkSubmitAction包含的3种行为,下面以行为SparkSubmitAction.SUBMIT为例进行分析,其他行为也可以从各自的具体处理代码进行分析。

对应处理SparkSubmitAction.SUBMIT行为的代码入口点为submit(appArgs),进入该方法,即进入提交应用程序的处理方法的具体代码如下。

978-7-111-55442-4-Chapter03-27.jpg

978-7-111-55442-4-Chapter03-28.jpg

其中,最终运行所需的参数都由prepareSubmitEnvironment方法负责解析和转换,然后根据其结果执行。解析的结果包含以下4部分。(www.xing528.com)

·子进程运行所需的参数。

·子进程运行时的classpath列表。

·系统属性的映射。

·子进程运行时的主类。

解析之后调用runMain方法,该方法中除了一些环境设置等操作外,最终会调用解析得到的childMainClass的main方法。下面简单分析一下prepareSubmitEnvironment方法,通过该方法来了解SparkSubmit是如何帮助底层的集群管理器和部署模式的封装。接下来以不同集群管理器和部署模式下最终运行的childMainClass类的解析为主线进行分析。

1)当部署模式为Client时,将childMainClass设置为传入的mainClass,对应代码如下。

978-7-111-55442-4-Chapter03-29.jpg

2)当集群管理器为Standalone、部署模式为Cluster时,根据提交的两种方式将childMa-inClass分别设置为不同的类,同时将传入的args.mainClass(提交应用程序时所设置的主类)及其参数根据不同集群管理器与部署模式进行转换,并封装到新的主类所需的参数中。对应的设置如表3-3所示。

表3-3 Standalone+Cluster时两种不同提交方式下的childMainClass封装

978-7-111-55442-4-Chapter03-30.jpg

表3-3中,REST(representational State Transfer,表述性状态传递)是Roy Fielding博士在2000年他的论文中提出来的一种软件架构网格。

这些设置的主类相当于封装了应用程序提交时的主类,运行后负责向Master结点申请启动提交的应用程序。

3)当集群管理器为YARN、部署模式为Cluster时,childMainClass及对应的mainClass的设置如表3-4所示。

表3-4 YARN+Cluster时childMainClass下的childMainClass封装

978-7-111-55442-4-Chapter03-31.jpg

4)当集群管理器为Mesos、部署模式为Cluster时,childMainClass及对应的mainClass的设置如表3-5所示。

表3-5 Mesos+Cluster时childMainClass下的childMainClass封装

978-7-111-55442-4-Chapter03-32.jpg

从上面的分析可以看到,当使用Clinet部署模式进行提交时,由于设置的childMainClass为应用程序提交时的主类,因此是直接在提交点执行设置的主类,即mainClass。当使用Cluster部署模式进行提交时,则会根据具体集群管理器等信息使用相应的封装类。这些封装类会向集群申请提交应用程序的请求,然后在由集群调度分配得到的结点上启动所申请的应用程序。

以将封装类设置为"org.apache.spark.deploy.Client"为例,从该类主入口main方法查看,可以看到构建了一个ClientEndpoint实例,在构建该实例时,会将提交应用程序时设置的mainClass等信息封装到DriverDescription实例中,然后发送到Master,申请执行用户提交的应用程序。

对应各种集群管理器与部署模式的组合,实际代码中的处理细节非常多。这里仅仅给出了一种源代码阅读的方式,和对应的大数据处理一样,通常采用化繁为简的方式去阅读复杂的源代码。比如这里在理解了整个大框架的调用过程后,以childMainClass的设置作为主线去解读源代码,相应的,在扩展阅读其他源代码时,也可以采用这种方式,以某种集群管理器与部署模式为主线,详细阅读相关的代码。最后,在了解各种组合的处理细节之后,通过对比、抽象等方法,对整个SparkSubmit进行归纳总结即可。

参考3.4.1部署框架一章中的集群部署组件图(图3-2),可以看到提交的应用程序的驱动程序(Driver Program)部分对应包含了一个SparkContext实例。因此接下来从该实例出发,解析驱动程序在不同的集群管理器的部署细节。

4.SparkContext解析

在详细解析SparkContext实例之前,首先来看下SparkContext类的注释部分,具体如下。

978-7-111-55442-4-Chapter03-33.jpg

SparkContext类是Spark功能的主入口点。一个SparkContext实例代表了与一个Spark集群的连接,并且通过该实例可以在集群中构建RDD、累加器及广播变量。SparkContext实例的构建参数config,描述了应用程序的Spark配置。在该参数中指定的配置属性会覆盖默认的配置属性及系统属性。

在SparkContext类文件中,定义了一个描述集群管理器类型的单例对象SparkMasterRe-gex,在该对象中详细给出了当前Spark所支持的各种集群管理器类型,具体代码如下。

978-7-111-55442-4-Chapter03-34.jpg

978-7-111-55442-4-Chapter03-35.jpg

在SparkContext类中的主要流程可以归纳如下。

1)createSparkEnv:创建Spark的执行环境对应的SparkEnv实例。

对应代码如下。

978-7-111-55442-4-Chapter03-36.jpg

2)createTaskScheduler:创建作业调度器实例。

对应代码如下。

978-7-111-55442-4-Chapter03-37.jpg

其中,TaskScheduler是低层次的任务调度器,负责任务的调度。通过该接口提供可插拔的任务调度器。每个TaskScheduler负责调度一个SparkContext实例中的任务,负责调度上层DAG调度器中每个Stage提交的任务集(TaskSet),并将这些任务提交到集群中运行,在任务提交执行时可以使用失败重试机制设置失败重试的次数。上述对应高层的DAG调度器的实例构建请参见下一步。

3)newDAGScheduler:创建高层Stage调度的DAG调度器实例。

对应代码如下。

978-7-111-55442-4-Chapter03-38.jpg

DAGScheduler是高层调度模块,负责作业(Job)的Stage拆分,以及最终将Stage对应的任务集提交到低层次的任务调度器上。

下面基于这些主要流程,针对SparkMasterRegex单例对象中给出的各种集群部署模式进行解析。对应不同集群模式下,这些流程中构建了包括TaskScheduler与SchedulerBackend的不同的具体子类,所构建的相关实例具体如表3-6所示。

表3-6 各种情况下TaskScheduler与SchedulerBackend的不同的具体子类

978-7-111-55442-4-Chapter03-39.jpg

与TaskScheduler与SchedulerBackend不同的是,在不同集群模式中,应用程序的高层调度器DAGScheduler的实例是相同的,即对应在Spark on YARN与Mesos等集群管理器中,应用程序内部的高层Stage调度是相同的。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈