Spark源码(1)- Master的启动(standalone)

此源码版本为2.1.0,若有不准确的地方,欢迎各位指点!

spark的启动是通过${SPARK_HOME}/sbin目录下的start-all.sh来启动的,它调用了spark-config.sh,start-master.sh,start-slaves.sh三个脚本。

spark-config.sh中加载的就是一些配置信息和环境变量。
start-master.sh和start-slaves.sh是启动master和worker进程的脚本。

master通过start-master.sh这个脚本来启动。

CLASS="org.apache.spark.deploy.master.Master"

......

"${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS 1 \
  --ip $SPARK_MASTER_IP --port $SPARK_MASTER_PORT --webui-port $SPARK_MASTER_WEBUI_PORT \
  $ORIGINAL_ARGS

在这里通过class指定的路径调用了master这个类,传入如ip,port等参数,这里首先会运行master的伴生类的main方法

  • 初始化日志信息
  • 读取配置文件
  • 创建RPC通信系统
/**
 * RpcEnv包含了如下三大核心:
 * 1.RpcEndpoint 消息循环体,负责接收并处理消息。Spark中的Master、Worker都是RpcEndpoint 。
 * 2.RpcEndpointRef :RpcEndpoint的引用,如果需要和RpcEndpoint通信,
 * 就必须获取它的RpcEndpointRef,通过RpcEndpointRef发送消息。
 * 3.Dispatcher:消息调度器,负责RPC消息路由到适当的RpcEndpoint。
  */
private[deploy] object Master extends Logging {
  val SYSTEM_NAME = "sparkMaster"
  val ENDPOINT_NAME = "Master"

  def main(argStrings: Array[String]) {
    // 初始化log对象
    Utils.initDaemon(log)
    val conf = new SparkConf
    // MasterArguments类在new一个对象的时候会先读取spark-env.sh中的配置信息,然后再读取
    // spark-defaults.conf中的数据,然后在获取通过shell传入的参数,如果有重复的值,那么后面的会覆盖前面的值。
    // 所以spark中配置信息获取的优先性为:传入参数 > spark-defaults.conf > spark-env.sh
    // 构建Master的参数
    val args = new MasterArguments(argStrings, conf)
    // 创建RpcEnv和Endpoint,spark在akka或netty的基础上封装了一个RPC系统,它负责spark的各个进程之间的通信
    // 指定的主机名必须是start-master.sh脚本运行的本地机器名称
    val (rpcEnv, _, _) = startRpcEnvAndEndpoint(args.host, args.port, args.webUiPort, conf)
    // 等待终止
    rpcEnv.awaitTermination()
  }

main方法调用了startRpcEnvAndEndpoint方法来开启RPC,这里查看一下此方法的源代码

  • 创建Spark安全管理类 - SecurityManager
  • 创建RPC的server端 - RpcEnv
  • 创建RPC的client端 - Endpoint
  • 与master这个client端进行通信
/**
    * Start the Master and return a three tuple of:
    * (1) The Master RpcEnv
    * (2) The web UI bound port
    * (3) The REST server bound port, if any
    */
  def startRpcEnvAndEndpoint(
                              host: String,
                              port: Int,
                              webUiPort: Int,
                              conf: SparkConf): (RpcEnv, Int, Option[Int]) = {
    // spark中负责安全的类,集群中节点的交流,比如akka,netty的通信还有shuffle阶段
    // 使用的BlockTransferService的授权都是由这个类来管理的。
    val securityMgr = new SecurityManager(conf)
    // 首先创建RpcEnv,也就是server端
    val rpcEnv = RpcEnv.create(SYSTEM_NAME, host, port, conf, securityMgr)
    // 在RpcEnv中为当前的Master对象创建一个Endpoint,之后就可以直接根据这个Endpoint和Master通信了。
    val masterEndpoint = rpcEnv.setupEndpoint(ENDPOINT_NAME,
      new Master(rpcEnv, rpcEnv.address, webUiPort, securityMgr, conf))
    // 就是向masterEndpoint发送一个BoundPortsRequest,这里会返回一个BoundPortsResponse的信息
    val portsResponse = masterEndpoint.askWithRetry[BoundPortsResponse](BoundPortsRequest)
    (rpcEnv, portsResponse.webUIPort, portsResponse.restPort)
  }

master继承了ThreadSafeRpcEndpoint,所以它本身就是一个Endpoint了,在RPC Endpoint创建的时候,会调用这个Endpoint的OnStart方法。

  • 创建Spark的WebUI界面
  • 定时检查并删除死掉的worker进程
  • 创建StandaloneRestServer
  • 向测量系统注册,并启动
  • 创建standalone模式下的恢复机制
override def onStart(): Unit = {
    logInfo("Starting Spark master at " + masterUrl)
    logInfo(s"Running Spark version ${org.apache.spark.SPARK_VERSION}")
    // 创建MasterWebUI界面,也就是显示Master信息的页面
    webUi = new MasterWebUI(this, webUiPort)
    // 绑定web接口后面的Http server
    webUi.bind()
    // 通过访问这个url可以获取master的信息
    masterWebUiUrl = "http://" + masterPublicAddress + ":" + webUi.boundPort
    if (reverseProxy) {
      masterWebUiUrl = conf.get("spark.ui.reverseProxyUrl", masterWebUiUrl)
      logInfo(s"Spark Master is acting as a reverse proxy. Master, Workers and " +
        s"Applications UIs are available at $masterWebUiUrl")
    }
    // 按固定时间间隔检查并remove掉死掉的workers
    checkForWorkerTimeOutTask = forwardMessageThread.scheduleAtFixedRate(new Runnable {
      override def run(): Unit = Utils.tryLogNonFatalError {
        self.send(CheckForWorkerTimeOut)
      }
    }, 0, WORKER_TIMEOUT_MS, TimeUnit.MILLISECONDS)

    // 创建restServer,用于接收提交的application
    if (restServerEnabled) {
      val port = conf.getInt("spark.master.rest.port", 6066)
      restServer = Some(new StandaloneRestServer(address.host, port, conf, self, masterUrl))
    }
    // 启动restServer
    restServerBoundPort = restServer.map(_.start())

    // 向master的测量系统注册源
    masterMetricsSystem.registerSource(masterSource)
    // 启动master的测量系统
    masterMetricsSystem.start()
    // 启动application的测量系统
    applicationMetricsSystem.start()
    // Attach the master and app metrics servlet handler to the web ui after the metrics systems are
    // started.
    // 通过和attachHandler的绑定,可以把源信息展现在桌面上
    masterMetricsSystem.getServletHandlers.foreach(webUi.attachHandler)
    applicationMetricsSystem.getServletHandlers.foreach(webUi.attachHandler)

    // 之后就是standalone模式下恢复机制,(主要介绍下ZooKeeper的方式)
    val serializer = new JavaSerializer(conf)
    val (persistenceEngine_, leaderElectionAgent_) = RECOVERY_MODE match {
      case "ZOOKEEPER" =>
        logInfo("Persisting recovery state to ZooKeeper")
        //创建持久化引擎,用于持久化一些数据信息,如application,driverdeng
        //创建实现leader选举的类,用于在为leader的master出错后,选举别的master为leader
        val zkFactory =
        new ZooKeeperRecoveryModeFactory(conf, serializer)
        (zkFactory.createPersistenceEngine(), zkFactory.createLeaderElectionAgent(this))
      case "FILESYSTEM" =>
        val fsFactory =
          new FileSystemRecoveryModeFactory(conf, serializer)
        (fsFactory.createPersistenceEngine(), fsFactory.createLeaderElectionAgent(this))
      case "CUSTOM" =>
        val clazz = Utils.classForName(conf.get("spark.deploy.recoveryMode.factory"))
        val factory = clazz.getConstructor(classOf[SparkConf], classOf[Serializer])
          .newInstance(conf, serializer)
          .asInstanceOf[StandaloneRecoveryModeFactory]
        (factory.createPersistenceEngine(), factory.createLeaderElectionAgent(this))
      case _ =>
        (new BlackHolePersistenceEngine(), new MonarchyLeaderAgent(this))
    }
    persistenceEngine = persistenceEngine_
    leaderElectionAgent = leaderElectionAgent_
  }

到此master的启动已经完成,等待其它进程向其发送消息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值