热门标签 | 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通信终端(系统名+终端名),以及各个终端之间交互的信息(组件间的交互消息和应用调度相关的消息会在后续章节给出)这两个方面,来理清整个分布式集群中各个组件之间和内部的交互逻辑,进而把握整个调度机制。




推荐阅读
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文总结了Java中日期格式化的常用方法,并给出了示例代码。通过使用SimpleDateFormat类和jstl fmt标签库,可以实现日期的格式化和显示。在页面中添加相应的标签库引用后,可以使用不同的日期格式化样式来显示当前年份和月份。该文提供了详细的代码示例和说明。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了在Java中gt、gtgt、gtgtgt和lt之间的区别。通过解释符号的含义和使用例子,帮助读者理解这些符号在二进制表示和移位操作中的作用。同时,文章还提到了负数的补码表示和移位操作的限制。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了在Spring 3.1中,数据源未能自动连接到@Configuration类的错误原因,并提供了解决方法。作者发现了错误的原因,并在代码中手动定义了PersistenceAnnotationBeanPostProcessor。作者删除了该定义后,问题得到解决。此外,作者还指出了默认的PersistenceAnnotationBeanPostProcessor的注册方式,并提供了自定义该bean定义的方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 标题: ... [详细]
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社区 版权所有