spark 是怎么跑在 yarn 上面的

spark on yarn 根据你启动的时候, 根据你 master 和 mode 参数, 来使用 客户端模式 还是 集群模式

客户端模式 yarn-client 集群模式 yarn-cluster

客户端模式, 是指 spark 的 driver jvm 进程 是跑着你运行 spark-submit 的那台机器上的, 一般是用于调试和交互,可以即时的看到输出, 启动后, 是不能停掉的当前的 shell 进程的, 不然 driver进程 也就被杀掉了,

集群模式 一般是用于生产环境, 如果用户提交作业后,就可以关掉 client 了, 因为这个时候 driver 是跑在集群中的某一台 node 上的, 所在的客户端已经完成使命了。

yarn 的规矩

在 yarn 上面提交运行一个应用的过程为

Client 向 YARN 提交应用程序,其中包括 ApplicationMaster 程序及启动 ApplicationMaster 的命令 ResourceManager 为该 ApplicationMaster 分配第一个 Container,并与对应的 NodeManager 通信,要求它在这个 Container 中启动应用程序的 ApplicationMaster ApplicationMaster 首先向 ResourceManager 注册 ApplicationMaster 为 Application 的任务申请并领取资源
领取到资源后,要求对应的 NodeManager 在 Container 中启动任务
NodeManager 收到 ApplicationMaster 的请求后,为任务设置好运行环境(包括环境变量、JAR 包、二进制程序等),将任务启动脚本写到一个脚本中,并通过运行该脚本启动任务 各个任务通过 RPC 协议向 ApplicationMaster 汇报自己的状态和进度,以让 ApplicationMaster 随时掌握各个任务的运行状态,从而可以在失败时重启任务 应用程序完成后,ApplicationMaster 向 ResourceManager 注销并关闭自己

无论 spark 以哪种方式启动, 只要是跑在 yarn 上面, 就得遵守yarn 的规矩, 所以 spark 能做的就是按照 yarn 的方式来适配,

spark-submit

这个工具是 spark 用来提交应用的一个工具, 它支持你把应用提交 在 local 上, mesos, 或者 yarn 上, 由于这个工具, 处理的corner case比较多, 所以代码也比较乱, 我简单梳理一下, spark-submit 使用反射机制启动用户作业的 main 函数, 如果是 yarn-cluser 模式就直接 启动 org.apache.spark.deploy.Client 类用户作业的类当参数带进去, 如果是 yarn-client 模式 ,就直接在本地启动用户作业的 main 函数,

org.apache.spark.deploy.Client 类里面针对两种模式会使用不同的运行不同的类,当做app master, 里面也调用不同的方法

val amClass = if (isClusterMode) { Utils.classForName("org.apache.spark.deploy.yarn.ApplicationMaster").getName } else { Utils.classForName("org.apache.spark.deploy.yarn.ExecutorLauncher").getName }```

if (isClusterMode) {

runDriver(securityMgr)

} else {

runExecutorLauncher(securityMgr)

}

```

集群模式 启动流程

上文我们提到了, 如果是 yarn-cluser 模式就启动 org.apache.spark.deploy.Client 类,

调用 client 的 submitApplication 方法, 在 ResourceManager 中创建一个 Application, 获取应用的ID, 判断资源管理集群是否能提供足够的资源, 判断我们应用申请的内存没有超过集群拥有的最大内存, 为 ApplicationMaster 封装一个容器, 这个容器包含启动的环境变量, java options 和启动的命令行, 也即是一个 ContainerLaunchContext, 创建一个 提交 yarn 应用的 ApplicationSubmissionContext, 包含ApplicationName ,yarn 队列和优先级, 应用的类型为 spark,

通过 yarnClient.submitApplication 提交应用到 ResourceManager, 这之后就跟 client 没有关系了, 终端关掉都没事。 因为是 cluster 模式, 所以 yarn 会申请一个 container 然后运行 ApplicationMaster 类, 里面会运行 runDriver 方法, 里面会启动 driver ,初始化 sparkcontext, 向 ResourceManager 注册, 设置 track url, 用来让用户查看运行情况, 然后向 RM 申请 资源, 包装运行 CoarseGrainedExecutorBackend 的 container 并提交启动,把 driver的 url当参数带进去 ,方便 executor 启动后向 driver 注册自己

客户端模式 启动流程

yarn-client 模式 ,就直接在本地启动用户作业的 main 函数, 用户程序里面会初始化 sparkContext, spark context 启动的时候会启动一些必要的组件, 会启动 taskScheduler和dagScheduler, 在创建taskScheduler的时候会根据我们传进来的master来选择Scheduler和SchedulerBackend。 由于我们选择的是yarn-client模式,程序会反射创建 YarnScheduler 和 YarnClientSchedulerBackend 类, 继承关系如下图

taskScheduler start 的时候, 也就是调用 TaskSchedulerImpl 的 start, 会 调用 YarnClientSchedulerBackend 的start 方法 SchedulerBackend启动的过程中将会初始化一些参数,封装在ClientArguments中,并将封装好的ClientArguments传进Client类中, 也会调用 Client 的 submitApplication 方法, 不同的是里面封装的容器启动的主类是 ExecutorLauncher 。 提交 application 到RM, 以上步骤都是运行在 提交所在机器上, driver 也是运行在了客户端, 客户端不能关闭, driver 的日志也是打印在客户端控制台, 经过 yarn 调度 am 运行在一个节点上, 里面运行 ExecutorLauncher -> runExecutorLauncher, 这个时候就不用运行 driver了, 只需要只需要把客户端 driver 的track url 注册到 RM, 申请contianer 启动 executor的时候,给的也是 运行在客户的 driver 的地址, 在这里只是应付 yarn 的规矩, 在 app master 上面跑一个 ExecutorLauncher, 连接 运行在客户端的 driver 和跑在申请资源里面的 executor, executor 启动后向运行在客户端的 driver 注册自己

原创精品,首发个人公众号 spark技术分享 , 同步个人网站 coolplayer.net ,未经本人同意,禁止一切转载

本文由 华盟网 作者:小龙 发表,其版权均为 华盟网 所有,文章内容系作者个人观点,不代表 华盟网 对观点赞同或支持。如需转载,请注明文章来源。

0

发表评论

// 360自动收录 // 360自动收录