Worker作为对于Spark集群的健壮运行起着举足轻重的作用,作为Master的奴隶,每15s向Master告诉自己还活着,一旦主人(Master》有了任务(Application),立马交给属于它的奴隶们(Workers),那么奴隶们就会数数自己有多少家当(比如内存、核数),量力而行地交给主人完成的任务,如果奴隶不量力而行在执行任务过程中不幸死了的话,作为主人的Master只会等待60s,如果奴隶在这生死攸关的紧要关头不理睬主人,那么主人只能认为它死了,那么就会把它抛弃了。下面,我们一起了解一下Worker究竟有哪些不为人知的故事。

1.家当(静态属性)

我们只列出一些重要的属性:
1.一个守护单线程的调度器用于在特殊的时间发送消息,执行的任务包括:向Master注册Worker信息、发送心跳信息、定期清理任务等。
  private val forwordMessageScheduler =
    ThreadUtils.newDaemonSingleThreadScheduledExecutor("worker-forward-message-scheduler")
2.一个独立的线程用于清理工作空间,执行任务:定期清理执行过程中创建的本地文件。
  private val cleanupThreadExecutor = ExecutionContext.fromExecutorService(
    ThreadUtils.newDaemonSingleThreadExecutor("worker-cleanup-thread"))
3.shuffle服务默认没有开启除非用户自己配置,之所以会开启外部的Shuffle服务,是为了避免Executor进程任务过重,导致不能为其他的Executor提供Shuffle数据,影响任务的执行。比如,如果使用YARN模式时,可以在yarn-site.xml文件中配置及其端口号,从而在NodeManger上开启Shuffle服务,减轻Executor的负担。
  private val shuffleService = new ExternalShuffleService(conf, securityMgr)
4.一个masters的线程池。因为master注册Worker是一个阻塞操作,所以这个线程池必须能同时创建"masterRpcAddresses.size"大小的线程,这样我们就能将worker注册到所有的master上。
private val registerMasterThreadPool = new ThreadPoolExecutor(
    0,
    masterRpcAddresses.size, // Make sure we can register with all masters at the same time
    60L, TimeUnit.SECONDS,
    new SynchronousQueue[Runnable](),
    ThreadUtils.namedThreadFactory("worker-register-master-threadpool"))

2.技能(方法)

由于Worker本质上是一个RpcEndpoint,所以我们按照它的声明周期进行介绍。
1.构造函数就是Worker默认的构造器
2.onStart方法


<code>
//worker的启动
  override def onStart() {
    assert(!registered)
    logInfo("Starting Spark worker %s:%d with %d cores, %s RAM".format(
      host, port, cores, Utils.megabytesToString(memory)))
    logInfo(s"Running Spark version ${org.apache.spark.SPARK_VERSION}")
    logInfo("Spark home: " + sparkHome)
    createWorkDir()
    //如果用户已经配置外部的Shuffle,那么就启动该服务
    shuffleService.startIfEnabled()
    //该WebUI只仅限于Standalone模式下
    webUi = new WorkerWebUI(this, workDir, webUiPort)
    webUi.bind()
    //将worker注册到master上,详情如下(1)
    registerWithMaster()
    metricsSystem.registerSource(workerSource)
    metricsSystem.start()
    //metricsSystem启动后,将worker的metrics的servlet handler添加到web ui
    metricsSystem.getServletHandlers.foreach(webUi.attachHandler)
  }
</code>


(1)将worker注册到master上的registerWithMaster()代码如下所示:


<code>
private def registerWithMaster() {
    //如果work与master可能多次失去连接,所以不要尝试太多次的注册
    registrationRetryTimer match {
      case None =>
        registered = false
        //将woker注册到所有的master上返回一个Future的数组,详情如下(2)
        registerMasterFutures = tryRegisterAllMasters()
        connectionAttemptCount = 0
        //一个单线程不定时向master发送注册信息
        registrationRetryTimer = Some(forwordMessageScheduler.scheduleAtFixedRate(
          new Runnable {
            override def run(): Unit = Utils.tryLogNonFatalError {
              Option(self).foreach(_.send(ReregisterWithMaster))
            }
          },
          INITIAL_REGISTRATION_RETRY_INTERVAL_SECONDS,
          INITIAL_REGISTRATION_RETRY_INTERVAL_SECONDS,
          TimeUnit.SECONDS))
      case Some(_) =>
        logInfo("Not spawning another attempt to register with the master, since there is an" +
          " attempt scheduled already.")
    }
  }
</code>


(2)tryRegisterAllMasters代码如下:


<code>
//将worker注册到所有的master上面
  private def tryRegisterAllMasters(): Array[JFuture[_]] = {
    masterRpcAddresses.map { masterAddress =>
      registerMasterThreadPool.submit(new Runnable {
        override def run(): Unit = {
          try {
            logInfo("Connecting to master " + masterAddress + "...")
            //在Client的Rpc中根据master的systemname、address、endpointname返回一个master的远程引用
            val masterEndpoint =
              rpcEnv.setupEndpointRef(Master.SYSTEM_NAME, masterAddress, Master.ENDPOINT_NAME)
            //调用master的远程引用将worker注册到master上
            masterEndpoint.send(RegisterWorker(
              workerId, host, port, self, cores, memory, webUi.boundPort, publicAddress))
          } catch {
            case ie: InterruptedException => // Cancelled
            case NonFatal(e) => logWarning(s"Failed to connect to master $masterAddress", e)
          }
        }
      })
    }
  }
</code>


3.onStop()方法,把关于Worker的一切都停止掉,比如线程、executors、drivers、shuffleService等


<code>
override def onStop() {
    cleanupThreadExecutor.shutdownNow()
    metricsSystem.report()
    cancelLastRegistrationRetry()
    forwordMessageScheduler.shutdownNow()
    registerMasterThreadPool.shutdownNow()
    executors.values.foreach(_.kill())
    drivers.values.foreach(_.kill())
    shuffleService.stop()
    webUi.stop()
    metricsSystem.stop()
  }
</code>


还有一个很重要的receive方法,都放到这儿可能有点拥挤,留到下一篇吧。

【原】 Spark中Worker源码分析(一)的更多相关文章

  1. 【原】 Spark中Worker源码分析(二)

    继续前一篇的内容.前一篇内容为: Spark中Worker源码分析(一)http://www.cnblogs.com/yourarebest/p/5300202.html 4.receive方法, r ...

  2. 【原】Spark中Client源码分析(二)

    继续前一篇的内容.前一篇内容为: Spark中Client源码分析(一)http://www.cnblogs.com/yourarebest/p/5313006.html DriverClient中的 ...

  3. 【原】Spark中Master源码分析(二)

    继续上一篇的内容.上一篇的内容为: Spark中Master源码分析(一) http://www.cnblogs.com/yourarebest/p/5312965.html 4.receive方法, ...

  4. 【原】Spark中Master源码分析(一)

    Master作为集群的Manager,对于集群的健壮运行发挥着十分重要的作用.下面,我们一起了解一下Master是听从Client(Leader)的号召,如何管理好Worker的吧. 1.家当(静态属 ...

  5. Spark中决策树源码分析

    1.Example 使用Spark MLlib中决策树分类器API,训练出一个决策树模型,使用Python开发. """ Decision Tree Classifica ...

  6. 【原】Spark中Client源码分析(一)

    在Spark Standalone中我们所谓的Client,它的任务其实是由AppClient和DriverClient共同完成的.AppClient是一个允许app(Client)和Spark集群通 ...

  7. Spark Scheduler模块源码分析之DAGScheduler

    本文主要结合Spark-1.6.0的源码,对Spark中任务调度模块的执行过程进行分析.Spark Application在遇到Action操作时才会真正的提交任务并进行计算.这时Spark会根据Ac ...

  8. Spark RPC框架源码分析(三)Spark心跳机制分析

    一.Spark心跳概述 前面两节中介绍了Spark RPC的基本知识,以及深入剖析了Spark RPC中一些源码的实现流程. 具体可以看这里: Spark RPC框架源码分析(二)运行时序 Spark ...

  9. Spark Scheduler模块源码分析之TaskScheduler和SchedulerBackend

    本文是Scheduler模块源码分析的第二篇,第一篇Spark Scheduler模块源码分析之DAGScheduler主要分析了DAGScheduler.本文接下来结合Spark-1.6.0的源码继 ...

随机推荐

  1. [CSS]visibility 属性

    定义和用法 visibility 属性规定元素是否可见. 提示:即使不可见的元素也会占据页面上的空间.请使用 "display" 属性来创建不占据页面空间的不可见元素. 说明 这个 ...

  2. 如何把jar包放到本地maven仓库中

    以前开发过程中也碰到过maven项目中需要引用其它jar包的情况,当时由于对maven还不熟悉,所以使用了在本地搭建nexus或者手动添加jar包的方法,两者都不是很方便. 如今因为淘宝的工作需要,又 ...

  3. Nginx+uWSIG+Django+websocket的实现

    1.Django+websocket django-websocket dwebsocket django-websocket是旧版的,现在已经没有人维护,dwebsocket是新版的,推荐使用dwe ...

  4. C++ 输入输出文件流(ifstream&ofstream)

    ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间; 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O, ...

  5. 2014年度辛星css教程夏季版第四节

    接下来的这一节我计划讲解的是超链接和列表的样式,然后我们做出一个导航栏出来,其实导航栏是非常常见的,但是我们这里做得这个有点并不那么完善,等我们学完了css之后再完善它. ************** ...

  6. 更改Keil工程名

    假设原工程名为A,需要改成B. 1, 在工程目录下,把A.vuopt和A.uvproj改成B.uvopt和B.uvproj. 2,删除其他A文件. 3,打开工程B.然后修改下面位置: Project ...

  7. cocos2dx3.4 解析json文件

    头文件: #include "json/document.h" #include "json/stringbuffer.h" #include "js ...

  8. 原生 JavaScript 图片裁剪效果

    图片裁剪程序效果如下,可鼠标操作.   拖动左边小方框时在右侧实时显示对应的裁剪图片,同时左侧的拖动框里图片完全显示,拖动框外部图片模糊显示.8个控制点可以对显示区域大小进行控制. HTML 和 CS ...

  9. display:inline-block元素间空白间隙问题

    display:inline-block元素间有空白间隙,可以在父元素上加font-size:0

  10. quicksort+binarySearch

    描述 数轴上有n个点,对于任一闭区间 [a, b],试计算落在其内的点数. 输入 第一行包括两个整数:点的总数n,查询的次数m. 第二行包含n个数,为各个点的坐标. 以下m行,各包含两个整数:查询区间 ...