热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Spark(1.6版本)系列:SparkStandalone部署之应用程序的两种部署方式(一)

SparkStandalone部署之应用程序的两种部署方式

1.4.2       应用程序的部署

和其他常见的分布式集群类似,Spark Standalone集群的部署也是采用典型的Master/Slave架构。其中,Master节点负责整个集群的资源管理与调度,Worker节点(也可以称Slave节点)在Master节点的调度下启动Executor,负责执行具体工作(包括应用程序以及应用程序提交的任务)。

从前面的分析中抽取出Spark Standalone模式部署的TaskSchedulerSchedulerBackend具体子类的实例构建信息,如表1-8所示:

1-8 SparkStandalone模式部署具体子类的构建

部署模式(master)

实例对应的类

备注

Spark Standalone

taskSchedulerTaskSchedulerImpl

_schedulerBackendSparkDeploySchedulerBackend

Spark Standalone对应Spark原生的完全分布式集群。

因此,此种方式下不需要像上面的本地伪分布式集群那样,构建一个虚拟的本地集群。

下面以提交请求的行为为例,结合应用程序提交时所使用的不同部署模式,给出详细的框架及其描述,对应在框架中的其他请求与此类似,可以自行解析。

1.       Client的部署模式提交应用程序

Client的部署模式提交时,直接在提交点运行应用程序,即对应的驱动程序是在当前节点启动的。启动一个应用程序后,就涉及到各个相关的方面,包含应用运行的环境、应用元数据的清理、状态监听、DAG调度、任务调度等等。这些具体的内容,在后续的章节中都会分别给出有针对性的解析,故此处仅针对必要的信息,来加深对Spark Standalone集群部署方面的理解。

对应的部署与执行框架如图1-3所示:

                           

1-3 Client部署模式下的部署与执行框架

如图1-3所示,在驱动程序(DriverProgram)内部会构建一个SparkContext实例,前面章节已经分析过,在SparkContext实例的主要流程中,会构建出用于任务调度的TaskScheduler实例、用于DAG调度的DAGScheduler实例,以及作为TaskSchedulerImpl底层的一个可插拔的调度系统终端的SparkDeploySchedulerBackend实例。由于调度系统后续会以单独一章篇幅进行解析,因此这里仅仅给出简单的部署与交互过程,具体过程如下所示:

1)SparkContext构建出SparkDeploySchedulerBackend实例后,然后调用该实例的start方法,关键代码如下所示:

1.         override def start() {

2.           super.start()

3.           launcherBackend.connect()

4.         ……

5.           // 封装的命令,该命令发送到Worker节点,并根据获取的资源启动后,相当于

6.           // 打开了一个通信通道。

7.         val command =  Command("org.apache.spark.executor.CoarseGrainedExecutorBackend",

8.               args, sc.executorEnvs, classPathEntries  ++ testingClassPath, libraryPathEntries, javaOpts)

9.             val appUIAddress =  sc.ui.map(_.appUIAddress).getOrElse("")

10.          val coresPerExecutor =  conf.getOption("spark.executor.cores").map(_.toInt)

11.      // 通过ApplicationDescriptioncommand封装起来

12.      val appDesc = new ApplicationDescription(sc.appName,  maxCores, sc.executorMemory,

13.            command, appUIAddress, sc.eventLogDir,  sc.eventLogCodec, coresPerExecutor)

14.       

15.      // 构建一个作为应用程序客户端的AppClient实例,并将this设置为该实例的监听

16.      // 器,AppClient实例内部会将Executor端的消息转发给this

17.       client = new AppClient(sc.env.rpcEnv,  masters, appDesc, this, conf)

18.          client.start()

19.          launcherBackend.setState(SparkAppHandle.State.SUBMITTED)

20.          waitForRegistration()

21.          launcherBackend.setState(SparkAppHandle.State.RUNNING)

其中,AppClient实例在调用方法start时,会构建一个RPC通信终端,即ClientEndpoint实例,实例化后再自动调用onStart(),这时候就会将封装的ApplicationDescription实例进一步封装到消息RegisterApplications的实例中,然后由该RPC通信终端将该信息发送到MasterRPC通信终端。

2)MasterRPC通信终端在收到RegisterApplications消息后,通过资源调度方法,最终会调用launchExecutor方法,在该方法中再向调度所分配到的Worker节点的RPC通信终端发送LaunchExecutor消息。

3)WorkerRPC通信终端在收到LaunchExecutor消息后,会实例化ExecutorRunner对象,然后启动一个线程,在线程中解析RegisterApplications消息封装的ApplicationDescription实例所携带的Command实例。也就是前面封装的CoarseGrainedExecutorBackend类,最后启动CoarseGrainedExecutorBackend类的进程。进程的入口就是CoarseGrainedExecutorBackend伴生对象的main函数

4)在入口处,即CoarseGrainedExecutorBackend伴生对象的main函数中,会解析参数,然后调用run函数,在该run函数中会构建CoarseGrainedExecutorBackend实例,也就是构建一个RPC通信终端。Run方法中的关键代码如下所示:

1.               env.rpcEnv.setupEndpoint("Executor",  new CoarseGrainedExecutorBackend(

2.                 env.rpcEnv, driverUrl, executorId,  sparkHostPort, cores, userClassPath, env))

3.               workerUrl.foreach { url =>

4.                 env.rpcEnv.setupEndpoint("WorkerWatcher",  new WorkerWatcher(env.rpcEnv, url))

5.               }

其中,driverUrl是封装CoarseGrainedExecutorBackendCommand时设置的,可以回到前面SparkDeploySchedulerBackend实例的start方法,在构建Command之前,设置了一些参数,对应代码如下:

1.             // The endpoint for executors to talk to  us

2.             val driverUrl =  rpcEnv.uriOf(SparkEnv.driverActorSystemName,

3.               RpcAddress(sc.conf.get("spark.driver.host"),  sc.conf.get("spark.driver.port").toInt),

4.         CoarseGrainedSchedulerBackend.ENDPOINT_NAME)

5.             val args = Seq(

6.          "--driver-url",  driverUrl,

7.               "--executor-id",  "{{EXECUTOR_ID}}",

8.               "--hostname",  "{{HOSTNAME}}",

9.               "--cores",  "{{CORES}}",

10.            "--app-id", "{{APP_ID}}",

11.            "--worker-url",  "{{WORKER_URL}}")

其中,第46行就是封装的与CoarseGrainedExecutorBackend进行通信的终端及其对应参数的选项名称,也就是前面的CoarseGrainedSchedulerBackend实例的driverEndpoint : DriverEndpoint成员,对应在Spark Standalone部署模式下,就是具体子类SparkDeploySchedulerBackend

5)对应CoarseGrainedExecutorBackendRPC通信终端,在实例化时自动调用onStart方法。在该方法中向driverUrl发送RegisterExecutor消息。这里的driverUrl就是上一步分析得到的驱动程序端的SparkDeploySchedulerBackendRPC通信端口driverEndpoint

6)SparkDeploySchedulerBackend实例收到RegisterExecutor消息时,表示当前有可用资源注册上来,此时即可开始作业的调度。具体的调度过程可以参考本书的调度章节。

说明:分布式消息间的调度是建立在消息事件的基础上的,可以通过列举所有的RPC通信终端(系统名+终端名),以及各个终端之间交互的信息(组件间的交互消息和应用调度相关的消息会在后续章节给出)这两个方面,来理清整个分布式集群中各个组件之间和内部的交互逻辑,进而把握整个调度机制。




推荐阅读
  • 云原生应用最佳开发实践之十二原则(12factor)
    目录简介一、基准代码二、依赖三、配置四、后端配置五、构建、发布、运行六、进程七、端口绑定八、并发九、易处理十、开发与线上环境等价十一、日志十二、进程管理当 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • 《Spark核心技术与高级应用》——1.2节Spark的重要扩展
    本节书摘来自华章社区《Spark核心技术与高级应用》一书中的第1章,第1.2节Spark的重要扩展,作者于俊向海代其锋马海平,更多章节内容可以访问云栖社区“华章社区”公众号查看1. ... [详细]
  • 开发笔记:Spark Java API 之 CountVectorizer
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了SparkJavaAPI之CountVectorizer相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 本文总结了初学者在使用dubbo设计架构过程中遇到的问题,并提供了相应的解决方法。问题包括传输字节流限制、分布式事务、序列化、多点部署、zk端口冲突、服务失败请求3次机制以及启动时检查。通过解决这些问题,初学者能够更好地理解和应用dubbo设计架构。 ... [详细]
  • [翻译]微服务设计模式5. 服务发现服务端服务发现
    服务之间需要互相调用,在单体架构中,服务之间的互相调用直接通过编程语言层面的方法调用就搞定了。在传统的分布式应用的部署中,服务地 ... [详细]
  • 精讲代理设计模式
    代理设计模式为其他对象提供一种代理以控制对这个对象的访问。代理模式实现原理代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色ÿ ... [详细]
  • 后台自动化测试与持续部署实践
    后台自动化测试与持续部署实践https:mp.weixin.qq.comslqwGUCKZM0AvEw_xh-7BDA后台自动化测试与持续部署实践原创 腾讯程序员 腾讯技术工程 2 ... [详细]
  • 项目需要将音视频文件上传服务器,考虑并发要求高,通过七牛来实现。直接上代码usingQiniu.IO;usingQiniu.IO.Resumable;usingQiniu.RPC; ... [详细]
author-avatar
潇洒D-An_na
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有