前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住给大家分享一下。点击跳转到网站:https://www.captainai.net/dongkelun
前言
在上一篇文章 Spark 源码 | 脚本分析总结(一) 中,我们分析了 Spark 的脚本执行流程,最终都通过 spark-class 启动 org.apache.spark.deploy.SparkSubmit,本文我们继续分析 SparkSubmit 的提交流程,看看它是如何根据不同的 clusterManager 和 deployMode 来提交应用的。
版本
Spark 3.2.3
SparkSubmit 入口
根据脚本分析,我们知道 spark-submit 最终通过 spark-class 启动 org.apache.spark.deploy.SparkSubmit,入口方法为 main:
1 | // SparkSubmit.scala |
doSubmit 方法是真正的入口:
1 | def doSubmit(args: Array[String]): Unit = { |
参数解析
parseArguments 方法创建 SparkSubmitArguments 对象,解析命令行参数,将在下一篇文章中单独分析
1 | protected def parseArguments(args: Array[String]): SparkSubmitArguments = { |
SparkSubmitArguments 解析后的参数包括(以 spark-shell 为例):
1 | master: yarn |
提交流程
1. submit 方法
submit 方法是提交流程的统一入口,主要处理:
- Standalone Cluster 模式特殊处理:支持 REST API 提交,失败时回退到 Legacy 方式
- 调用 doRunMain:内嵌函数,最终执行 runMain
调用链:submit → doRunMain → runMain → prepareSubmitEnvironment(prepareSubmitEnvironment 在 runMain 中调用)
1 | /** |
2. prepareSubmitEnvironment 方法
这是核心方法,根据不同的 clusterManager 和 deployMode 准备提交环境,返回:
- childArgs: 运行主类的参数
- childClasspath: 主类的 jar
- sparkConf: Spark 配置
- childMainClass: 主类的全路径
2.1 解析 clusterManager 和 deployMode
1 | // 设置集群管理器 |
2.2 计算模式标志
1 | val isYarnCluster = clusterManager == YARN && deployMode == CLUSTER |
2.3 Client 模式
Client 模式与 Cluster 模式的区别:
- Client 模式:直接启动用户传入的主类(
args.mainClass) - Cluster 模式:启动包装类,用户主类作为参数传入
例如 spark-shell 提交时,args.mainClass 为 org.apache.spark.repl.Main,详情可参考 Spark 源码 | 脚本分析总结(一)
1 | // In client mode, childMainClass equals the user-provided main class directly |
2.4 Yarn Cluster 模式
1 | // In yarn-cluster mode, use yarn.Client as a wrapper around the user class |
Yarn Cluster 模式下,childMainClass 变为 org.apache.spark.deploy.yarn.YarnClusterApplication,用户的主类作为参数传入。
2.5 Standalone Cluster 模式
1 | // In standalone cluster mode, use the REST client to submit the application (Spark 1.3+). |
Standalone Cluster 模式有两种方式:
- REST API:使用 RestSubmissionClientApp
- Legacy:使用 ClientApp
3. runMain 方法
runMain 方法真正启动应用:
1 | private def runMain(args: SparkSubmitArguments, uninitLog: Boolean): Unit = { |
关键逻辑:
- 加载主类(childMainClass)
- 如果主类实现了 SparkApplication 接口,直接实例化
- 否则包装成 JavaMainApplication
- 调用 app.start 启动应用
不同模式的 childMainClass
| 模式 | childMainClass |
|---|---|
| Client (Yarn/Standalone/Mesos/K8s/Local) | 用户传入的主类(如 org.apache.spark.repl.Main) |
| Yarn Cluster | org.apache.spark.deploy.yarn.YarnClusterApplication |
| Mesos Cluster | org.apache.spark.deploy.rest.RestSubmissionClientApp |
| Standalone Cluster (REST) | org.apache.spark.deploy.rest.RestSubmissionClientApp |
| Standalone Cluster (Legacy) | org.apache.spark.deploy.ClientApp |
| K8s Cluster | org.apache.spark.deploy.k8s.submit.KubernetesClientApplication |
总结
通过本文的分析,我们了解了 SparkSubmit 的提交流程:
- 入口:spark-submit → spark-class → SparkSubmit.main → doSubmit
- 参数解析:parseArguments 解析命令行参数(将在下一篇文章中单独分析)
- submit 方法:
- 处理代理用户(proxyUser)切换
- Standalone Cluster 模式支持 REST API,失败时回退到 Legacy
- 注意:submit 本身不区分模式,所有模式都会调用 runMain
- 环境准备:prepareSubmitEnvironment 根据 clusterManager + deployMode 设置 childMainClass 和 childArgs(这是真正的模式区分点)
- 应用启动:runMain 加载 childMainClass 并启动
流程说明:
- submit 方法是统一的入口,无论 Client 还是 Cluster 模式,最终都会调用 runMain
- runMain 调用 prepareSubmitEnvironment,在其中根据 clusterManager + deployMode 决定:
- Client 模式:childMainClass = 用户传入的主类(如 org.apache.spark.repl.Main)
- Cluster 模式:childMainClass = 包装类(如 YarnClusterApplication),用户主类作为参数传入
- 最后加载 childMainClass 并启动
下一次我们将分析参数解析详细过程,然后分别分析 Yarn Client、Yarn Cluster、Standalone Client、Standalone Cluster 模式的详细提交流程。