// 启动 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对象创建一个Endpoint,Master就是一个Endpoint,Worker可以与其进行通信;
在这里,调用了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.")
}
}
//onStart()函数
registerWithMaster()
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
}
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)