master节点启动
根据脚本定位到master启动类为 org.apache.spark.deploy.master.Master
定位到启动类后,就可以开始入手源码了。
找到Master 的入口类
def main(argStrings: Array[String]) {
/* ... 省略 */
// 直接跳转至下面那个函数
val (rpcEnv, _, _) = startRpcEnvAndEndpoint(args.host, args.port, args.webUiPort, conf)
rpcEnv.awaitTermination()
}
/** 注释描述也很清晰
* 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]) = {
val securityMgr = new SecurityManager(conf)
// 创建rpc 环境
val rpcEnv = RpcEnv.create(SYSTEM_NAME, host, port, conf, securityMgr)
/**
* rpcEnv启动对应节点
* 内部实际上是 NettyRpcEnv 中 节点在distpatcher上的注册
*/
val masterEndpoint = rpcEnv.setupEndpoint(ENDPOINT_NAME,
new Master(rpcEnv, rpcEnv.address, webUiPort, securityMgr, conf))
val portsResponse = masterEndpoint.askSync[BoundPortsResponse](BoundPortsRequest)
(rpcEnv, portsResponse.webUIPort, portsResponse.restPort)
}
创建RpcEnv 网络通信环境
- 首先RpcEnv 创建通过NettyRpcEnvFactory的create() 创建对应的 NettyRpcEnv 实体
def create(config: RpcEnvConfig): RpcEnv = {
/* ... 省略 */
// 此处创建对应的NettyRpcEnv 实体
val nettyEnv =
new NettyRpcEnv(sparkConf, javaSerializerInstance, config.advertiseAddress,
config.securityManager, config.numUsableCores)
if (!config.clientMode) {
val startNettyRpcEnv: Int => (NettyRpcEnv, Int) = { actualPort =>
// 启动服务的函数 ,会初始化一个 TransportServer 用于节点之间的io
nettyEnv.startServer(config.bindAddress, actualPort)
(nettyEnv, nettyEnv.address.port)
}
try {
//启动对应服务的方法
Utils.startServiceOnPort(config.port, startNettyRpcEnv, sparkConf, config.name)._1
}/* ... 省略 */
nettyEnv
}
NettyRpcEnv 内部会有初始化分发器dispatcher(分发器) 、TransportServer(传输服务端)、TansportContext(传输上下文)、outboxes(对外传输通信的发件箱)
类org.apache.spark.rpc.netty.NettyRpcEnv
//分发器
private val dispatcher: Dispatcher = new Dispatcher(this, numUsableCores)
//传输上下文
private val transportContext = new TransportContext(transportConf,
new NettyRpcHandler(dispatcher, this, streamManager))
//传输服务端
@volatile private var server: TransportServer = _
// 数据传输的发件箱
private val outboxes = new ConcurrentHashMap[RpcAddress, Outbox]()
创建NettyRpcEnv实例对象后,直接通过工具类开启服务startNettyRpcEnv
- 通过transportContext 创建TransportServer(封装了netty核心服务)
- 将已经创建的分发器Dispatcher 注册 RpcEndpoint(可以理解为接收信息的的站点),
def startServer(bindAddress: String, port: Int): Unit = {
// 忽略。。
val bootstraps: java.util.List[TransportServerBootstrap] =
if (securityManager.isAuthenticationEnabled()) {
java.util.Arrays.asList(new AuthServerBootstrap(transportConf, securityManager))
} else {
java.util.Collections.emptyList()
}
// NettyRpcEnv类内部创建传输服务端
//内部创建TransportServer
//初始化Netty ServerBootstrap
//至此
server = transportContext.createServer(bindAddress, port, bootstraps)
//分发器注册
dispatcher.registerRpcEndpoint(
RpcEndpointVerifier.NAME, new RpcEndpointVerifier(this, dispatcher))
}
- 创建对应的传输通道,绑定端口
Utils.startServiceOnPort(config.port, startNettyRpcEnv, sparkConf, config.name)
至此,rpcEnv初始化完毕
完成流程看下图