Spark的启动部分源码解析(org.apache.spark.deploy.master.Master,org.apache.spark.deploy.master.Worker)

Master

入口函数:

 

  // 启动 Master 的入口函数
    def main(argStrings: Array[String]) {
        Utils.initDaemon(log)
        val conf = new SparkConf
        // 构建用于参数解析的实例   --host hadoop102 --port 7077 --webui-port 8080
        val args = new MasterArguments(argStrings, conf)
        // 启动 RPC 通信环境和 MasterEndPoint(通信终端)
        val (rpcEnv, _, _) = startRpcEnvAndEndpoint(args.host, args.port, args.webUiPort, conf)
        rpcEnv.awaitTermination()
    }

Master启动时首先创建一个RpcEnv对象,负责管理所有通信逻辑;

Master通过RpcEnv对象创建一个EndpointMaster就是一个EndpointWorker可以与其进行通信;

startRpcEnvAndEndpoint

在这里,调用了startRpcEnvAndEndpoint这个函数,这个函数的内容如下

 def startRpcEnvAndEndpoint(
                                  host: String,
                                  port: Int,
                                  webUiPort: Int,
                                  conf: SparkConf): (RpcEnv, Int, Option[Int]) = {
        val securityMgr = new SecurityManager(conf)
        // 创建 Master 端的 RpcEnv 环境   参数:SYSTEM_NAME = "sparkMaster" hadoop102 7077 conf securityMgr
    
        val rpcEnv: RpcEnv = RpcEnv.create(SYSTEM_NAME, host, port, conf, securityMgr)
        // 创建 Master对象, 该对象就是一个 RpcEndpoint, 在 RpcEnv中注册这个RpcEndpoint
        // 返回该 RpcEndpoint 的引用, 使用该引用来接收信息和发送信息
        val masterEndpoint: RpcEndpointRef = rpcEnv.setupEndpoint(ENDPOINT_NAME,
            new Master(rpcEnv, rpcEnv.address, webUiPort, securityMgr, conf))
        // 向 Master 的通信终端发法请求,获取 BoundPortsResponse 对象
        // BoundPortsResponse 是一个样例类包含三个属性: rpcEndpointPort webUIPort restPort
        val portsResponse: BoundPortsResponse = masterEndpoint.askWithRetry[BoundPortsResponse](BoundPortsRequest)
        (rpcEnv, portsResponse.webUIPort, portsResponse.restPort)
    }

接收worker的心跳

case Heartbeat(workerId, worker) =>
            idToWorker.get(workerId) match {
                case Some(workerInfo) =>
                    // 记录该 Worker 的最新心跳
                    workerInfo.lastHeartbeat = System.currentTimeMillis()
                case None =>
                    if (workers.map(_.id).contains(workerId)) {
                        logWarning(s"Got heartbeat from unregistered worker $workerId." +
                            " Asking it to re-register.")
                        worker.send(ReconnectWorker(masterUrl))
                    } else {
                        logWarning(s"Got heartbeat from unregistered worker $workerId." +
                            " This worker was never registered, so ignoring the heartbeat.")
                    }
            }

Worker:

向master注册

//onStart()函数
registerWithMaster()

main中创建一个RpcEnv对象,负责管理所有通信逻辑,再创建一个Endpoint

def main(argStrings: Array[String]) {
        Utils.initDaemon(log)
        val conf = new SparkConf
        // 构建解析参数的实例
        val args = new WorkerArguments(argStrings, conf)
        // 启动 Rpc 环境和 Rpc 终端
        val rpcEnv = startRpcEnvAndEndpoint(args.host, args.port, args.webUiPort, args.cores,
            args.memory, args.masters, args.workDir, conf = conf)
        rpcEnv.awaitTermination()
    }
//worker的startRpcEnvAndEndpoint:
 def startRpcEnvAndEndpoint(
                                  host: String,
                                  port: Int,
                                  webUiPort: Int,
                                  cores: Int,
                                  memory: Int,
                                  masterUrls: Array[String],
                                  workDir: String,
                                  workerNumber: Option[Int] = None,
                                  conf: SparkConf = new SparkConf): RpcEnv = {

        // The LocalSparkCluster runs multiple local sparkWorkerX RPC Environments
        val systemName = SYSTEM_NAME + workerNumber.map(_.toString).getOrElse("")
        val securityMgr = new SecurityManager(conf)
        // 创建 RpcEnv 实例  参数: "sparkWorker", "hadoop102", 8081, conf, securityMgr
        val rpcEnv = RpcEnv.create(systemName, host, port, conf, securityMgr)
        // 根据传入 masterUrls 得到 masterAddresses.  就是从命令行中传递过来的 Master 地址
        val masterAddresses = masterUrls.map(RpcAddress.fromSparkURL(_))
        // 最终实例化 Worker 得到 Worker 的 RpcEndpoint
        rpcEnv.setupEndpoint(ENDPOINT_NAME, new Worker(rpcEnv, webUiPort, cores, memory,
            masterAddresses, ENDPOINT_NAME, workDir, conf, securityMgr))
        rpcEnv
    }

master注册并且接收到了master的恢复信息后,更新注册状态,并开始向master发送心跳。

 logInfo("Successfully registered with master " + masterRef.address.toSparkURL)
                // 已经注册过了
                registered = true
                // 更新 Master
                changeMaster(masterRef, masterWebUiUrl)
                // 通知自己给 Master 发送心跳信息  默认 1 分钟 4 次
                forwordMessageScheduler.scheduleAtFixedRate(new Runnable {
                    override def run(): Unit = Utils.tryLogNonFatalError {
                        self.send(SendHeartbeat)
                    }
                }, 0, HEARTBEAT_MILLIS, TimeUnit.MILLISECONDS)

 

你可能感兴趣的:(大数据,Spark,spark)