spark源码分析—spark core(一):集群启动

spark集群通过spark的start-all.sh脚本进行启动,所以首先我们看一下该脚本的内容,该脚本内容很简单,它会通过调用相同目录下的start-master.sh脚本启动spark Master服务,调用start-slaves.sh脚本启动spark Worker服务。大家注意start-master.sh脚本只会在调用该脚本的机器启动Mater服务,如果Master是HA的话,需要到另外的配置为Master的机器调用start-master.sh脚本启动。所以start-all.sh脚本只能启动非HA的spark集群的所有Master和Worker服务,这和Hadoop的脚本有些区别,不知道社区是故意为之还是因为其他的理由。
接下来我们分析一下spark集群启动相关的脚本的内容。

start-all.sh脚本片段
if [ -z "${SPARK_HOME}" ]; then
  export SPARK_HOME="$(cd "`dirname "$0"`"/..; pwd)"
fi

# 加载spark的配置的环境变量,主要加载SPARK_HOME、
# SPARK_CONF_DIR和一下python相关的环境变量
. "${SPARK_HOME}/sbin/spark-config.sh"

# 调用start-master.sh脚本启动spark的master服务,
# 且Master服务在该脚本被调用的机器上启动
"${SPARK_HOME}/sbin"/start-master.sh

# 调用start-slaves.sh脚本启动所用的Worker服务,
# 该脚本会调用slaves.sh脚本,通过ssh发送Worker服务启动命令
"${SPARK_HOME}/sbin"/start-slaves.sh

接下来分别对Master和Worker服务的启动流程进行分析

1、Master启动

我们从start-master.sh脚本开始一步一步分析。

spark-master.sh脚本片段
# 启动Master服务需要调用的Scala主类
CLASS="org.apache.spark.deploy.master.Master"
# start-master.sh脚本会调用spark-daemon.sh脚本,spark-daemon.sh脚本,
# spark-daemon.sh脚本又会调用spark-class.sh脚本,并将参数传到该脚本,
# spark-class.sh脚本会调用Spark的org.apache.spark.launcher.Main类对不同的CLASS、不同的OS生成合适的启动服务进程的java命令
# Usage: spark-daemon.sh [--config <conf-dir>] (start|stop|submit|status) <spark-command> <spark-instance-number> <args...>
"${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS 1 \
  --host $SPARK_MASTER_HOST --port $SPARK_MASTER_PORT --webui-port $SPARK_MASTER_WEBUI_PORT \
  $ORIGINAL_ARGS

spark-daemon.sh脚本和spark-class.sh脚本就不再分析,感兴趣的可以看一下。接下来看一下org.apache.spark.deploy.master.Master类的main方法,看一下Master的启动流程

def main(argStrings: Array[String]) {
    // 注册Master进程的Logger对象,用于处理该进程的“TERM”,“HUP”,“INT”事件,并打印事件到日志
    Utils.initDaemon(log)
    // 创建SparkConf对象,该对象会加载Spark的所有配置参数,并保存在ConcurrentHashMap对象中
    val conf = new SparkConf
    // 创建MasterArguments对象,该对象会对Master的参数进行解析
    val args = new MasterArguments(argStrings, conf)
   // 创建一个RPC环境,并启动Master的RPC端点服务且注册到该RPC环境中
    val (rpcEnv, _, _) = startRpcEnvAndEndpoint(args.host, args.port, args.webUiPort, conf)
   // 阻塞等待RPC环境结束
    rpcEnv.awaitTermination()
  }

接下来,看一下startRpcEnvAndEndpoint()方法,该方法会创建RPC环境和Master端点服务的注册流程,RpcEnv底层就是一个Netty实现的Socket服务,通过不同的rpc endpoint注册信息进行路由,对于不同的Socket请求调用不同的处理逻辑。Spark从2.+开始集群的RPC抛弃了Akka,通过Netty实现了一套简化版的Akka RPC框架。后边会分析具体的实现,在这里只要知道它是一个RPC服务即可。

def startRpcEnvAndEndpoint(
      host: String,
      port: Int,
      webUiPort: Int,
      conf: SparkConf): (RpcEnv, Int, Option[Int]) = {
    // 创建SecurityManager对象,负责Spark不同组件之间的的安全通行
    val securityMgr = new SecurityManager(conf)
    // 创建RPCEnv,用于RPC服务,spark从2.+开始实现了自己的基于Netty的类Akka的RPC框架,不再使用Akka
    val rpcEnv = RpcEnv.create(SYSTEM_NAME, host, port, conf, securityMgr)
    // 创建、注册Master服务的RPC端点并启动
    val masterEndpoint = rpcEnv.setupEndpoint(ENDPOINT_NAME,
      new Master(rpcEnv, rpcEnv.address, webUiPort, securityMgr, conf))
   // 向Master发送同步RPC调用,获取Master服务的端口号
    val portsResponse = masterEndpoint.askSync[BoundPortsResponse](BoundPortsRequest)
    (rpcEnv, portsResponse.webUIPort, portsResponse.restPort)
  }

貌似到执行完startRpcEnvAndEndpoint()方法就结束了,但是事实上不是这样的。

前面说了,Spark RPC服务和Akka类似,所以在Master endpoint启动后RPC框架会立即调用该endpoint的onStart()方法,因此Master的启动还没有结束,接下来继续看一下Master类的onStart()方法有什么东东吧

override def onStart(): Unit = {
    // 打印Master启动日志
    logInfo("Starting Spark master at " + masterUrl)
    logInfo(s"Running Spark version ${org.apache.spark.SPARK_VERSION}")
    // 创建MasterWebUI服务,并绑定端口启动,其实底层就是一个基于Jetty的web服务,
    // 而这个就是我们在浏览器输入spark_master_url:spark_master_port访问的web服务
    webUi = new MasterWebUI(this, webUiPort)
    webUi.bind()
    masterWebUiUrl = "http://" + masterPublicAddress + ":" + webUi.boundPort
   // 如果使用反向代理,masterWebUI地址使用代理地址
    if (reverseProxy) {
      masterWebUiUrl = conf.get(
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值