最近准备把自己看大神源码的一些心得总结写下来,平时看了总是会忘记,记下来,随时翻出来看看。
第一篇讲Spark中最重要的SparkContext,他是Spark的核心,虽说在Spark2中已经用SparkSession来作为我们初始化的对象,但是最最核心核心的还是SparkContext。
SparkContext有一个参数SparkConf 是一个存储运行参数的地方,这个参数是不能在运行中修改的,对外调用的方法中都是SparkConf的clone,SparkConf有三个重要的参数,spark.master,spark.submit.deployMode,spark.app.name。
源码如下所示:
def master: String = _conf.get("spark.master")
def deployMode: String = _conf.getOption("spark.submit.deployMode").getOrElse("client")
def appName: String = _conf.get("spark.app.name")
master代表有local,standalone,yarn,mesos
deployment有client和cluster。
SparkContext有以下几个重要组件
1,_env: SparkEnv
2,_schedulerBackend: SchedulerBackend
3,_taskScheduler: TaskScheduler
4,_dagScheduler: DAGScheduler
5,_executorAllocationManager: Option[ExecutorAllocationManager]
6,_listenerBus: LiveListenerBus
7,_statusTracker: SparkStatusTracker
这里看一下_schedulerBackend,_taskScheduler和_dagScheduler的初始化
val (sched, ts) = SparkContext.createTaskScheduler(this, master, deployMode)
这里返回的是一个元组tuple赋值给我们的两个变量,
_schedulerBackend = sched
_taskScheduler = ts
以及生成 _dagScheduler
_dagScheduler = new DAGScheduler(this)
createTaskScheduler方法是依据设置的master和deployment来获取对应的实现类
这里主要讲一下Spark On Yarn的获取方式
case masterUrl =>
val cm = getClusterManager(masterUrl) match {
case Some(clusterMgr) => clusterMgr
case None => throw new SparkException("Could not parse Master URL: '" + master + "'")
}
try {
val scheduler = cm.createTaskScheduler(sc, masterUrl)
val backend = cm.createSchedulerBackend(sc, masterUrl, scheduler)
cm.initialize(scheduler, backend)
(backend, scheduler)
} catch {
case se: SparkException => throw se
case NonFatal(e) =>
throw new SparkException("External scheduler cannot be instantiated", e)
}
getClusterManager方法根据master参数返回对应的Clustermanager,通过ServiceLoader加载了所有的ExternalClusterManager实现类通过其canCreate方法过滤出我们想要的。这里的得到的是YarnClusterManager 这个类的 canCreate如下
override def canCreate(masterURL: String): Boolean = {
masterURL == "yarn"
}
TaskScheduler的生成方法:
override def createTaskScheduler(sc: SparkContext, masterURL: String): TaskScheduler = {
sc.deployMode match {
case "cluster" => new YarnClusterScheduler(sc)
case "client" => new YarnScheduler(sc)
case _ => throw new SparkException(s"Unknown deploy mode '${sc.deployMode}' for Yarn")
}
}
可见如果是Spark on Yarn的cluster模式返回YarnClusterScheduler如果是client模式返回YarnScheduler,YarnClusterScheduler是YarnScheduler的子类,YarnClusterScheduler重写了postStartHook方法,
override def postStartHook() {
//这里是给Yarn-Cluster模式下ApplicationMaster的sc赋值说明sc已经初始化完毕
ApplicationMaster.sparkContextInitialized(sc)
super.postStartHook()//调用父类的postStartHook方法
logInfo("YarnClusterScheduler.postStartHook done")
}
YarnScheduler是TaskSchedulerImpl的子类,重写了父类的getRackForHost
// By default, rack is unknown
override def getRackForHost(hostPort: String): Option[String] = {
val host = Utils.parseHostPort(hostPort)._1
Option(RackResolver.resolve(sc.hadoopConfiguration, host).getNetworkLocation)
}
父类TaskSchedulerImpl是管理Task的类
因为Yarn支持机架感知所有只有SparkOnYarn 才有这个功能
SchedulerBackend的生成方法
override def createSchedulerBackend(sc: SparkContext,
masterURL: String,
scheduler: TaskScheduler): SchedulerBackend = {
sc.deployMode match {
case "cluster" =>
new YarnClusterSchedulerBackend(scheduler.asInstanceOf[TaskSchedulerImpl], sc)
case "client" =>
new YarnClientSchedulerBackend(scheduler.asInstanceOf[TaskSchedulerImpl], sc)
case _ =>
throw new SparkException(s"Unknown deploy mode '${sc.deployMode}' for Yarn")
}
}
很明显Yarn-Cluster返回YarnClusterSchedulerBackend,Yarn-Client返回YarnClientSchedulerBackend 然后SchedulerBackend会作为TaskScheduler初始化initialize参数,后面再写。
_dagScheduler直接用 new DAGScheduler(this)方式赋值,这个是生成DAG有向无环图的类